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