76
76
77
77
#define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */
78
78
#define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */
79
+ #define PCPU_ATOMIC_MAP_MARGIN_LOW 32
80
+ #define PCPU_ATOMIC_MAP_MARGIN_HIGH 64
79
81
80
82
#ifdef CONFIG_SMP
81
83
/* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */
@@ -102,9 +104,12 @@ struct pcpu_chunk {
102
104
int free_size ; /* free bytes in the chunk */
103
105
int contig_hint ; /* max contiguous size hint */
104
106
void * base_addr ; /* base address of this chunk */
107
+
105
108
int map_used ; /* # of map entries used before the sentry */
106
109
int map_alloc ; /* # of map entries allocated */
107
110
int * map ; /* allocation map */
111
+ struct work_struct map_extend_work ;/* async ->map[] extension */
112
+
108
113
void * data ; /* chunk data */
109
114
int first_free ; /* no free below this */
110
115
bool immutable ; /* no [de]population allowed */
@@ -318,9 +323,14 @@ static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot)
318
323
/**
319
324
* pcpu_need_to_extend - determine whether chunk area map needs to be extended
320
325
* @chunk: chunk of interest
326
+ * @is_atomic: the allocation context
321
327
*
322
- * Determine whether area map of @chunk needs to be extended to
323
- * accommodate a new allocation.
328
+ * Determine whether area map of @chunk needs to be extended. If
329
+ * @is_atomic, only the amount necessary for a new allocation is
330
+ * considered; however, async extension is scheduled if the left amount is
331
+ * low. If !@is_atomic, it aims for more empty space. Combined, this
332
+ * ensures that the map is likely to have enough available space to
333
+ * accomodate atomic allocations which can't extend maps directly.
324
334
*
325
335
* CONTEXT:
326
336
* pcpu_lock.
@@ -329,15 +339,25 @@ static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot)
329
339
* New target map allocation length if extension is necessary, 0
330
340
* otherwise.
331
341
*/
332
- static int pcpu_need_to_extend (struct pcpu_chunk * chunk )
342
+ static int pcpu_need_to_extend (struct pcpu_chunk * chunk , bool is_atomic )
333
343
{
334
- int new_alloc ;
344
+ int margin , new_alloc ;
345
+
346
+ if (is_atomic ) {
347
+ margin = 3 ;
335
348
336
- if (chunk -> map_alloc >= chunk -> map_used + 3 )
349
+ if (chunk -> map_alloc <
350
+ chunk -> map_used + PCPU_ATOMIC_MAP_MARGIN_LOW )
351
+ schedule_work (& chunk -> map_extend_work );
352
+ } else {
353
+ margin = PCPU_ATOMIC_MAP_MARGIN_HIGH ;
354
+ }
355
+
356
+ if (chunk -> map_alloc >= chunk -> map_used + margin )
337
357
return 0 ;
338
358
339
359
new_alloc = PCPU_DFL_MAP_ALLOC ;
340
- while (new_alloc < chunk -> map_used + 3 )
360
+ while (new_alloc < chunk -> map_used + margin )
341
361
new_alloc *= 2 ;
342
362
343
363
return new_alloc ;
@@ -394,6 +414,20 @@ static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc)
394
414
return 0 ;
395
415
}
396
416
417
+ static void pcpu_map_extend_workfn (struct work_struct * work )
418
+ {
419
+ struct pcpu_chunk * chunk = container_of (work , struct pcpu_chunk ,
420
+ map_extend_work );
421
+ int new_alloc ;
422
+
423
+ spin_lock_irq (& pcpu_lock );
424
+ new_alloc = pcpu_need_to_extend (chunk , false);
425
+ spin_unlock_irq (& pcpu_lock );
426
+
427
+ if (new_alloc )
428
+ pcpu_extend_area_map (chunk , new_alloc );
429
+ }
430
+
397
431
/**
398
432
* pcpu_fit_in_area - try to fit the requested allocation in a candidate area
399
433
* @chunk: chunk the candidate area belongs to
@@ -647,6 +681,7 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
647
681
chunk -> map_used = 1 ;
648
682
649
683
INIT_LIST_HEAD (& chunk -> list );
684
+ INIT_WORK (& chunk -> map_extend_work , pcpu_map_extend_workfn );
650
685
chunk -> free_size = pcpu_unit_size ;
651
686
chunk -> contig_hint = pcpu_unit_size ;
652
687
@@ -767,7 +802,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
767
802
goto fail_unlock ;
768
803
}
769
804
770
- while ((new_alloc = pcpu_need_to_extend (chunk ))) {
805
+ while ((new_alloc = pcpu_need_to_extend (chunk , is_atomic ))) {
771
806
spin_unlock_irqrestore (& pcpu_lock , flags );
772
807
if (is_atomic ||
773
808
pcpu_extend_area_map (chunk , new_alloc ) < 0 ) {
@@ -792,7 +827,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
792
827
if (size > chunk -> contig_hint )
793
828
continue ;
794
829
795
- new_alloc = pcpu_need_to_extend (chunk );
830
+ new_alloc = pcpu_need_to_extend (chunk , is_atomic );
796
831
if (new_alloc ) {
797
832
if (is_atomic )
798
833
continue ;
@@ -1418,6 +1453,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
1418
1453
*/
1419
1454
schunk = memblock_virt_alloc (pcpu_chunk_struct_size , 0 );
1420
1455
INIT_LIST_HEAD (& schunk -> list );
1456
+ INIT_WORK (& schunk -> map_extend_work , pcpu_map_extend_workfn );
1421
1457
schunk -> base_addr = base_addr ;
1422
1458
schunk -> map = smap ;
1423
1459
schunk -> map_alloc = ARRAY_SIZE (smap );
@@ -1446,6 +1482,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
1446
1482
if (dyn_size ) {
1447
1483
dchunk = memblock_virt_alloc (pcpu_chunk_struct_size , 0 );
1448
1484
INIT_LIST_HEAD (& dchunk -> list );
1485
+ INIT_WORK (& dchunk -> map_extend_work , pcpu_map_extend_workfn );
1449
1486
dchunk -> base_addr = base_addr ;
1450
1487
dchunk -> map = dmap ;
1451
1488
dchunk -> map_alloc = ARRAY_SIZE (dmap );
0 commit comments