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,21 @@ 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
+ if (* fd_size + extended_length > max_fd_size ) {
415
+ LOG_ERR ("cannot grow a file size beyond %zu" , max_fd_size );
416
+ return -1 ;
417
+ }
418
+
419
+ fd_offset = * fd_size ;
420
+ * fd_size += extended_length ;
421
+ }
422
+
423
+ void * ptr = os_mmap (hint_addr , extended_length , prot , flag , fd , fd_offset );
351
424
if (ptr == NULL ) {
425
+ LOG_PDEBUG ("memory mapping failed" );
352
426
return -1 ;
353
427
}
354
428
@@ -414,15 +488,17 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
414
488
return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
415
489
}
416
490
417
- int protection = os_provider -> protection ;
491
+ size_t fd_offset = os_provider -> size_fd ; // needed for critnib_insert()
418
492
419
493
void * addr = NULL ;
420
494
errno = 0 ;
421
- ret = os_mmap_aligned (NULL , size , alignment , page_size , protection , & addr );
495
+ ret = os_mmap_aligned (NULL , size , alignment , page_size ,
496
+ os_provider -> protection , os_provider -> visibility ,
497
+ os_provider -> fd , os_provider -> max_size_fd , & addr ,
498
+ & os_provider -> size_fd );
422
499
if (ret ) {
423
500
os_store_last_native_error (UMF_OS_RESULT_ERROR_ALLOC_FAILED , errno );
424
501
LOG_PERR ("memory allocation failed" );
425
-
426
502
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC ;
427
503
}
428
504
@@ -432,7 +508,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
432
508
LOG_ERR ("allocated address 0x%llx is not aligned to %zu (0x%zx) "
433
509
"bytes" ,
434
510
(unsigned long long )addr , alignment , alignment );
435
-
436
511
goto err_unmap ;
437
512
}
438
513
@@ -463,6 +538,18 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
463
538
}
464
539
}
465
540
541
+ if (os_provider -> fd > 0 ) {
542
+ // store (fd_offset + 1) to be able to store fd_offset == 0
543
+ ret =
544
+ critnib_insert (os_provider -> fd_offset_map , (uintptr_t )addr ,
545
+ (void * )(uintptr_t )(fd_offset + 1 ), 0 /* update */ );
546
+ if (ret ) {
547
+ LOG_ERR ("os_alloc(): inserting a value to the file descriptor "
548
+ "offset map failed (addr=%p, offset=%zu)" ,
549
+ addr , fd_offset );
550
+ }
551
+ }
552
+
466
553
* resultPtr = addr ;
467
554
468
555
return UMF_RESULT_SUCCESS ;
@@ -477,6 +564,12 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) {
477
564
return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
478
565
}
479
566
567
+ os_memory_provider_t * os_provider = (os_memory_provider_t * )provider ;
568
+
569
+ if (os_provider -> fd > 0 ) {
570
+ critnib_remove (os_provider -> fd_offset_map , (uintptr_t )ptr );
571
+ }
572
+
480
573
errno = 0 ;
481
574
int ret = os_munmap (ptr , size );
482
575
// ignore error when size == 0
@@ -581,23 +674,59 @@ static const char *os_get_name(void *provider) {
581
674
return "OS" ;
582
675
}
583
676
677
+ // This function is supposed to be thread-safe, so it should NOT be called concurrently
678
+ // with os_allocation_merge() with the same pointer.
584
679
static umf_result_t os_allocation_split (void * provider , void * ptr ,
585
680
size_t totalSize , size_t firstSize ) {
586
- (void )provider ;
587
- (void )ptr ;
588
681
(void )totalSize ;
589
- (void )firstSize ;
590
- // nop
682
+
683
+ os_memory_provider_t * os_provider = (os_memory_provider_t * )provider ;
684
+ if (os_provider -> fd <= 0 ) {
685
+ return UMF_RESULT_SUCCESS ;
686
+ }
687
+
688
+ void * value = critnib_get (os_provider -> fd_offset_map , (uintptr_t )ptr );
689
+ if (value == NULL ) {
690
+ LOG_ERR ("os_allocation_split(): getting a value from the file "
691
+ "descriptor offset map failed (addr=%p)" ,
692
+ ptr );
693
+ return UMF_RESULT_ERROR_UNKNOWN ;
694
+ } else {
695
+ uintptr_t new_key = (uintptr_t )ptr + firstSize ;
696
+ void * new_value = (void * )((uintptr_t )value + firstSize );
697
+ int ret = critnib_insert (os_provider -> fd_offset_map , new_key , new_value ,
698
+ 0 /* update */ );
699
+ if (ret ) {
700
+ LOG_ERR ("os_allocation_split(): inserting a value to the file "
701
+ "descriptor offset map failed (addr=%p, offset=%zu)" ,
702
+ (void * )new_key , (size_t )new_value - 1 );
703
+ return UMF_RESULT_ERROR_UNKNOWN ;
704
+ }
705
+ }
706
+
591
707
return UMF_RESULT_SUCCESS ;
592
708
}
593
709
710
+ // It should NOT be called concurrently with os_allocation_split() with the same pointer.
594
711
static umf_result_t os_allocation_merge (void * provider , void * lowPtr ,
595
712
void * highPtr , size_t totalSize ) {
596
- (void )provider ;
597
713
(void )lowPtr ;
598
- (void )highPtr ;
599
714
(void )totalSize ;
600
- // nop
715
+
716
+ os_memory_provider_t * os_provider = (os_memory_provider_t * )provider ;
717
+ if (os_provider -> fd <= 0 ) {
718
+ return UMF_RESULT_SUCCESS ;
719
+ }
720
+
721
+ void * value =
722
+ critnib_remove (os_provider -> fd_offset_map , (uintptr_t )highPtr );
723
+ if (value == NULL ) {
724
+ LOG_ERR ("os_allocation_merge(): removing a value from the file "
725
+ "descriptor offset map failed (addr=%p)" ,
726
+ highPtr );
727
+ return UMF_RESULT_ERROR_UNKNOWN ;
728
+ }
729
+
601
730
return UMF_RESULT_SUCCESS ;
602
731
}
603
732
0 commit comments