15
15
#include <string.h>
16
16
17
17
#include "base_alloc_global.h"
18
+ #include "critnib.h"
18
19
#include "provider_os_memory_internal.h"
19
20
#include "utils_log.h"
20
21
26
27
27
28
typedef struct os_memory_provider_t {
28
29
unsigned protection ; // combination of OS-specific protection flags
30
+ unsigned visibility ; // memory visibility mode
31
+ int fd ; // file descriptor for memory mapping
32
+ size_t size_fd ; // size of file used for memory mapping
33
+ size_t max_size_fd ; // maximum size of file used for memory mapping
34
+ // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset
35
+ // in order to be able to store fd_offset equal 0, because
36
+ // critnib_get() returns value or NULL, so a value cannot equal 0.
37
+ // It is needed mainly in the get_ipc_handle and open_ipc_handle hooks
38
+ // to mmap a specific part of a file.
39
+ critnib * fd_offset_map ;
29
40
30
41
// NUMA config
31
42
hwloc_bitmap_t nodeset ;
@@ -191,6 +202,34 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params,
191
202
return result ;
192
203
}
193
204
205
+ result = os_translate_mem_visibility_flag (in_params -> visibility ,
206
+ & provider -> visibility );
207
+ if (result != UMF_RESULT_SUCCESS ) {
208
+ LOG_ERR ("incorrect memory visibility flag: %u" , in_params -> visibility );
209
+ return result ;
210
+ }
211
+
212
+ provider -> fd = os_create_anonymous_fd (provider -> visibility );
213
+ if (provider -> fd == -1 ) {
214
+ LOG_ERR (
215
+ "creating an anonymous file descriptor for memory mapping failed" );
216
+ return UMF_RESULT_ERROR_UNKNOWN ;
217
+ }
218
+
219
+ provider -> size_fd = 0 ; // will be increased during each allocation
220
+ provider -> max_size_fd = get_max_file_size ();
221
+
222
+ if (provider -> fd > 0 ) {
223
+ int ret = os_set_file_size (provider -> fd , provider -> max_size_fd );
224
+ if (ret ) {
225
+ LOG_ERR ("setting file size %zu failed" , provider -> max_size_fd );
226
+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
227
+ }
228
+ }
229
+
230
+ LOG_DEBUG ("size of the memory mapped file set to %zu" ,
231
+ provider -> max_size_fd );
232
+
194
233
// NUMA config
195
234
int emptyNodeset = in_params -> numa_list_len == 0 ;
196
235
result = translate_numa_mode (in_params -> numa_mode , emptyNodeset ,
@@ -218,6 +257,14 @@ static umf_result_t os_initialize(void *params, void **provider) {
218
257
umf_os_memory_provider_params_t * in_params =
219
258
(umf_os_memory_provider_params_t * )params ;
220
259
260
+ if (in_params -> visibility == UMF_MEM_MAP_SHARED &&
261
+ in_params -> numa_mode != UMF_NUMA_MODE_DEFAULT ) {
262
+ LOG_ERR ("Unsupported NUMA mode for the UMF_MEM_MAP_SHARED memory "
263
+ "visibility mode (only the UMF_NUMA_MODE_DEFAULT is supported "
264
+ "for now)" );
265
+ return UMF_RESULT_ERROR_NOT_SUPPORTED ;
266
+ }
267
+
221
268
os_memory_provider_t * os_provider =
222
269
umf_ba_global_alloc (sizeof (os_memory_provider_t ));
223
270
if (!os_provider ) {
@@ -261,10 +308,19 @@ static umf_result_t os_initialize(void *params, void **provider) {
261
308
}
262
309
}
263
310
311
+ os_provider -> fd_offset_map = critnib_new ();
312
+ if (!os_provider -> fd_offset_map ) {
313
+ LOG_ERR ("creating file descriptor offset map failed" );
314
+ ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
315
+ goto err_free_nodeset_str_buf ;
316
+ }
317
+
264
318
* provider = os_provider ;
265
319
266
320
return UMF_RESULT_SUCCESS ;
267
321
322
+ err_free_nodeset_str_buf :
323
+ umf_ba_global_free (os_provider -> nodeset_str_buf );
268
324
err_destroy_hwloc_topology :
269
325
hwloc_topology_destroy (os_provider -> topo );
270
326
err_free_os_provider :
@@ -279,6 +335,9 @@ static void os_finalize(void *provider) {
279
335
}
280
336
281
337
os_memory_provider_t * os_provider = provider ;
338
+
339
+ critnib_delete (os_provider -> fd_offset_map );
340
+
282
341
if (os_provider -> nodeset_str_buf ) {
283
342
umf_ba_global_free (os_provider -> nodeset_str_buf );
284
343
}
@@ -334,7 +393,9 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) {
334
393
}
335
394
336
395
static int os_mmap_aligned (void * hint_addr , size_t length , size_t alignment ,
337
- size_t page_size , int prot , void * * out_addr ) {
396
+ size_t page_size , int prot , int flag , int fd ,
397
+ size_t max_fd_size , void * * out_addr ,
398
+ size_t * fd_size ) {
338
399
assert (out_addr );
339
400
340
401
size_t extended_length = length ;
@@ -347,8 +408,20 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment,
347
408
extended_length += alignment ;
348
409
}
349
410
350
- void * ptr = os_mmap (hint_addr , extended_length , prot );
411
+ size_t fd_offset = 0 ;
412
+
413
+ if (fd > 0 ) {
414
+ fd_offset = * fd_size ;
415
+ * fd_size += extended_length ;
416
+ if (* fd_size > max_fd_size ) {
417
+ LOG_ERR ("cannot grow a file size beyond %zu" , max_fd_size );
418
+ return -1 ;
419
+ }
420
+ }
421
+
422
+ void * ptr = os_mmap (hint_addr , extended_length , prot , flag , fd , fd_offset );
351
423
if (ptr == NULL ) {
424
+ LOG_PDEBUG ("memory mapping failed" );
352
425
return -1 ;
353
426
}
354
427
@@ -414,15 +487,17 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
414
487
return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
415
488
}
416
489
417
- int protection = os_provider -> protection ;
490
+ size_t fd_offset = os_provider -> size_fd ; // needed for critnib_insert()
418
491
419
492
void * addr = NULL ;
420
493
errno = 0 ;
421
- ret = os_mmap_aligned (NULL , size , alignment , page_size , protection , & addr );
494
+ ret = os_mmap_aligned (NULL , size , alignment , page_size ,
495
+ os_provider -> protection , os_provider -> visibility ,
496
+ os_provider -> fd , os_provider -> max_size_fd , & addr ,
497
+ & os_provider -> size_fd );
422
498
if (ret ) {
423
499
os_store_last_native_error (UMF_OS_RESULT_ERROR_ALLOC_FAILED , errno );
424
500
LOG_PERR ("memory allocation failed" );
425
-
426
501
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC ;
427
502
}
428
503
@@ -432,7 +507,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
432
507
LOG_ERR ("allocated address 0x%llx is not aligned to %zu (0x%zx) "
433
508
"bytes" ,
434
509
(unsigned long long )addr , alignment , alignment );
435
-
436
510
goto err_unmap ;
437
511
}
438
512
@@ -463,6 +537,18 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
463
537
}
464
538
}
465
539
540
+ if (os_provider -> fd > 0 ) {
541
+ // store (fd_offset + 1) to be able to store fd_offset == 0
542
+ ret =
543
+ critnib_insert (os_provider -> fd_offset_map , (uintptr_t )addr ,
544
+ (void * )(uintptr_t )(fd_offset + 1 ), 0 /* update */ );
545
+ if (ret ) {
546
+ LOG_ERR ("os_alloc(): inserting a value to the file descriptor "
547
+ "offset map failed (addr=%p, offset=%zu)" ,
548
+ addr , fd_offset );
549
+ }
550
+ }
551
+
466
552
* resultPtr = addr ;
467
553
468
554
return UMF_RESULT_SUCCESS ;
@@ -477,6 +563,12 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) {
477
563
return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
478
564
}
479
565
566
+ os_memory_provider_t * os_provider = (os_memory_provider_t * )provider ;
567
+
568
+ if (os_provider -> fd > 0 ) {
569
+ critnib_remove (os_provider -> fd_offset_map , (uintptr_t )ptr );
570
+ }
571
+
480
572
errno = 0 ;
481
573
int ret = os_munmap (ptr , size );
482
574
// ignore error when size == 0
@@ -581,23 +673,59 @@ static const char *os_get_name(void *provider) {
581
673
return "OS" ;
582
674
}
583
675
676
+ // This function is supposed to be thread-safe, so it should NOT be called concurrently
677
+ // with os_allocation_merge() with the same pointer.
584
678
static umf_result_t os_allocation_split (void * provider , void * ptr ,
585
679
size_t totalSize , size_t firstSize ) {
586
- (void )provider ;
587
- (void )ptr ;
588
680
(void )totalSize ;
589
- (void )firstSize ;
590
- // nop
681
+
682
+ os_memory_provider_t * os_provider = (os_memory_provider_t * )provider ;
683
+ if (os_provider -> fd <= 0 ) {
684
+ return UMF_RESULT_SUCCESS ;
685
+ }
686
+
687
+ void * value = critnib_get (os_provider -> fd_offset_map , (uintptr_t )ptr );
688
+ if (value == NULL ) {
689
+ LOG_ERR ("os_allocation_split(): getting a value from the file "
690
+ "descriptor offset map failed (addr=%p)" ,
691
+ ptr );
692
+ return UMF_RESULT_ERROR_UNKNOWN ;
693
+ } else {
694
+ uintptr_t new_key = (uintptr_t )ptr + firstSize ;
695
+ void * new_value = (void * )((uintptr_t )value + firstSize );
696
+ int ret = critnib_insert (os_provider -> fd_offset_map , new_key , new_value ,
697
+ 0 /* update */ );
698
+ if (ret ) {
699
+ LOG_ERR ("os_allocation_split(): inserting a value to the file "
700
+ "descriptor offset map failed (addr=%p, offset=%zu)" ,
701
+ (void * )new_key , (size_t )new_value - 1 );
702
+ return UMF_RESULT_ERROR_UNKNOWN ;
703
+ }
704
+ }
705
+
591
706
return UMF_RESULT_SUCCESS ;
592
707
}
593
708
709
+ // It should NOT be called concurrently with os_allocation_split() with the same pointer.
594
710
static umf_result_t os_allocation_merge (void * provider , void * lowPtr ,
595
711
void * highPtr , size_t totalSize ) {
596
- (void )provider ;
597
712
(void )lowPtr ;
598
- (void )highPtr ;
599
713
(void )totalSize ;
600
- // nop
714
+
715
+ os_memory_provider_t * os_provider = (os_memory_provider_t * )provider ;
716
+ if (os_provider -> fd <= 0 ) {
717
+ return UMF_RESULT_SUCCESS ;
718
+ }
719
+
720
+ void * value =
721
+ critnib_remove (os_provider -> fd_offset_map , (uintptr_t )highPtr );
722
+ if (value == NULL ) {
723
+ LOG_ERR ("os_allocation_merge(): removing a value from the file "
724
+ "descriptor offset map failed (addr=%p)" ,
725
+ highPtr );
726
+ return UMF_RESULT_ERROR_UNKNOWN ;
727
+ }
728
+
601
729
return UMF_RESULT_SUCCESS ;
602
730
}
603
731
0 commit comments