Skip to content

Commit b539b87

Browse files
committed
percpu: implmeent pcpu_nr_empty_pop_pages and chunk->nr_populated
pcpu_nr_empty_pop_pages counts the number of empty populated pages across all chunks and chunk->nr_populated counts the number of populated pages in a chunk. Both will be used to implement pre/async population for atomic allocations. pcpu_chunk_[de]populated() are added to update chunk->populated, chunk->nr_populated and pcpu_nr_empty_pop_pages together. All successful chunk [de]populations should be followed by the corresponding pcpu_chunk_[de]populated() calls. Signed-off-by: Tejun Heo <[email protected]>
1 parent 9c824b6 commit b539b87

File tree

2 files changed

+114
-10
lines changed

2 files changed

+114
-10
lines changed

mm/percpu-km.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ static struct pcpu_chunk *pcpu_create_chunk(void)
6969
chunk->base_addr = page_address(pages) - pcpu_group_offsets[0];
7070

7171
spin_lock_irq(&pcpu_lock);
72-
bitmap_fill(chunk->populated, nr_pages);
72+
pcpu_chunk_populated(chunk, 0, nr_pages);
7373
spin_unlock_irq(&pcpu_lock);
7474

7575
return chunk;

mm/percpu.c

Lines changed: 113 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct pcpu_chunk {
113113
void *data; /* chunk data */
114114
int first_free; /* no free below this */
115115
bool immutable; /* no [de]population allowed */
116+
int nr_populated; /* # of populated pages */
116117
unsigned long populated[]; /* populated bitmap */
117118
};
118119

@@ -161,6 +162,12 @@ static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop */
161162

162163
static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */
163164

165+
/*
166+
* The number of empty populated pages, protected by pcpu_lock. The
167+
* reserved chunk doesn't contribute to the count.
168+
*/
169+
static int pcpu_nr_empty_pop_pages;
170+
164171
/* reclaim work to release fully free chunks, scheduled from free path */
165172
static void pcpu_reclaim(struct work_struct *work);
166173
static DECLARE_WORK(pcpu_reclaim_work, pcpu_reclaim);
@@ -295,6 +302,38 @@ static void pcpu_mem_free(void *ptr, size_t size)
295302
vfree(ptr);
296303
}
297304

305+
/**
306+
* pcpu_count_occupied_pages - count the number of pages an area occupies
307+
* @chunk: chunk of interest
308+
* @i: index of the area in question
309+
*
310+
* Count the number of pages chunk's @i'th area occupies. When the area's
311+
* start and/or end address isn't aligned to page boundary, the straddled
312+
* page is included in the count iff the rest of the page is free.
313+
*/
314+
static int pcpu_count_occupied_pages(struct pcpu_chunk *chunk, int i)
315+
{
316+
int off = chunk->map[i] & ~1;
317+
int end = chunk->map[i + 1] & ~1;
318+
319+
if (!PAGE_ALIGNED(off) && i > 0) {
320+
int prev = chunk->map[i - 1];
321+
322+
if (!(prev & 1) && prev <= round_down(off, PAGE_SIZE))
323+
off = round_down(off, PAGE_SIZE);
324+
}
325+
326+
if (!PAGE_ALIGNED(end) && i + 1 < chunk->map_used) {
327+
int next = chunk->map[i + 1];
328+
int nend = chunk->map[i + 2] & ~1;
329+
330+
if (!(next & 1) && nend >= round_up(end, PAGE_SIZE))
331+
end = round_up(end, PAGE_SIZE);
332+
}
333+
334+
return max_t(int, PFN_DOWN(end) - PFN_UP(off), 0);
335+
}
336+
298337
/**
299338
* pcpu_chunk_relocate - put chunk in the appropriate chunk slot
300339
* @chunk: chunk of interest
@@ -483,6 +522,7 @@ static int pcpu_fit_in_area(struct pcpu_chunk *chunk, int off, int this_size,
483522
* @size: wanted size in bytes
484523
* @align: wanted align
485524
* @pop_only: allocate only from the populated area
525+
* @occ_pages_p: out param for the number of pages the area occupies
486526
*
487527
* Try to allocate @size bytes area aligned at @align from @chunk.
488528
* Note that this function only allocates the offset. It doesn't
@@ -498,7 +538,7 @@ static int pcpu_fit_in_area(struct pcpu_chunk *chunk, int off, int this_size,
498538
* found.
499539
*/
500540
static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align,
501-
bool pop_only)
541+
bool pop_only, int *occ_pages_p)
502542
{
503543
int oslot = pcpu_chunk_slot(chunk);
504544
int max_contig = 0;
@@ -587,6 +627,7 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align,
587627
chunk->free_size -= size;
588628
*p |= 1;
589629

630+
*occ_pages_p = pcpu_count_occupied_pages(chunk, i);
590631
pcpu_chunk_relocate(chunk, oslot);
591632
return off;
592633
}
@@ -602,6 +643,7 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align,
602643
* pcpu_free_area - free area to a pcpu_chunk
603644
* @chunk: chunk of interest
604645
* @freeme: offset of area to free
646+
* @occ_pages_p: out param for the number of pages the area occupies
605647
*
606648
* Free area starting from @freeme to @chunk. Note that this function
607649
* only modifies the allocation map. It doesn't depopulate or unmap
@@ -610,7 +652,8 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align,
610652
* CONTEXT:
611653
* pcpu_lock.
612654
*/
613-
static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
655+
static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme,
656+
int *occ_pages_p)
614657
{
615658
int oslot = pcpu_chunk_slot(chunk);
616659
int off = 0;
@@ -641,6 +684,8 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
641684
*p = off &= ~1;
642685
chunk->free_size += (p[1] & ~1) - off;
643686

687+
*occ_pages_p = pcpu_count_occupied_pages(chunk, i);
688+
644689
/* merge with next? */
645690
if (!(p[1] & 1))
646691
to_free++;
@@ -696,6 +741,50 @@ static void pcpu_free_chunk(struct pcpu_chunk *chunk)
696741
pcpu_mem_free(chunk, pcpu_chunk_struct_size);
697742
}
698743

744+
/**
745+
* pcpu_chunk_populated - post-population bookkeeping
746+
* @chunk: pcpu_chunk which got populated
747+
* @page_start: the start page
748+
* @page_end: the end page
749+
*
750+
* Pages in [@page_start,@page_end) have been populated to @chunk. Update
751+
* the bookkeeping information accordingly. Must be called after each
752+
* successful population.
753+
*/
754+
static void pcpu_chunk_populated(struct pcpu_chunk *chunk,
755+
int page_start, int page_end)
756+
{
757+
int nr = page_end - page_start;
758+
759+
lockdep_assert_held(&pcpu_lock);
760+
761+
bitmap_set(chunk->populated, page_start, nr);
762+
chunk->nr_populated += nr;
763+
pcpu_nr_empty_pop_pages += nr;
764+
}
765+
766+
/**
767+
* pcpu_chunk_depopulated - post-depopulation bookkeeping
768+
* @chunk: pcpu_chunk which got depopulated
769+
* @page_start: the start page
770+
* @page_end: the end page
771+
*
772+
* Pages in [@page_start,@page_end) have been depopulated from @chunk.
773+
* Update the bookkeeping information accordingly. Must be called after
774+
* each successful depopulation.
775+
*/
776+
static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk,
777+
int page_start, int page_end)
778+
{
779+
int nr = page_end - page_start;
780+
781+
lockdep_assert_held(&pcpu_lock);
782+
783+
bitmap_clear(chunk->populated, page_start, nr);
784+
chunk->nr_populated -= nr;
785+
pcpu_nr_empty_pop_pages -= nr;
786+
}
787+
699788
/*
700789
* Chunk management implementation.
701790
*
@@ -772,6 +861,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
772861
struct pcpu_chunk *chunk;
773862
const char *err;
774863
bool is_atomic = !(gfp & GFP_KERNEL);
864+
int occ_pages = 0;
775865
int slot, off, new_alloc, cpu, ret;
776866
unsigned long flags;
777867
void __percpu *ptr;
@@ -812,7 +902,8 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
812902
spin_lock_irqsave(&pcpu_lock, flags);
813903
}
814904

815-
off = pcpu_alloc_area(chunk, size, align, is_atomic);
905+
off = pcpu_alloc_area(chunk, size, align, is_atomic,
906+
&occ_pages);
816907
if (off >= 0)
817908
goto area_found;
818909

@@ -845,7 +936,8 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
845936
goto restart;
846937
}
847938

848-
off = pcpu_alloc_area(chunk, size, align, is_atomic);
939+
off = pcpu_alloc_area(chunk, size, align, is_atomic,
940+
&occ_pages);
849941
if (off >= 0)
850942
goto area_found;
851943
}
@@ -899,17 +991,20 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
899991
spin_lock_irqsave(&pcpu_lock, flags);
900992
if (ret) {
901993
mutex_unlock(&pcpu_alloc_mutex);
902-
pcpu_free_area(chunk, off);
994+
pcpu_free_area(chunk, off, &occ_pages);
903995
err = "failed to populate";
904996
goto fail_unlock;
905997
}
906-
bitmap_set(chunk->populated, rs, re - rs);
998+
pcpu_chunk_populated(chunk, rs, re);
907999
spin_unlock_irqrestore(&pcpu_lock, flags);
9081000
}
9091001

9101002
mutex_unlock(&pcpu_alloc_mutex);
9111003
}
9121004

1005+
if (chunk != pcpu_reserved_chunk)
1006+
pcpu_nr_empty_pop_pages -= occ_pages;
1007+
9131008
/* clear the areas and return address relative to base address */
9141009
for_each_possible_cpu(cpu)
9151010
memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size);
@@ -1019,7 +1114,9 @@ static void pcpu_reclaim(struct work_struct *work)
10191114

10201115
pcpu_for_each_pop_region(chunk, rs, re, 0, pcpu_unit_pages) {
10211116
pcpu_depopulate_chunk(chunk, rs, re);
1022-
bitmap_clear(chunk->populated, rs, re - rs);
1117+
spin_lock_irq(&pcpu_lock);
1118+
pcpu_chunk_depopulated(chunk, rs, re);
1119+
spin_unlock_irq(&pcpu_lock);
10231120
}
10241121
pcpu_destroy_chunk(chunk);
10251122
}
@@ -1041,7 +1138,7 @@ void free_percpu(void __percpu *ptr)
10411138
void *addr;
10421139
struct pcpu_chunk *chunk;
10431140
unsigned long flags;
1044-
int off;
1141+
int off, occ_pages;
10451142

10461143
if (!ptr)
10471144
return;
@@ -1055,7 +1152,10 @@ void free_percpu(void __percpu *ptr)
10551152
chunk = pcpu_chunk_addr_search(addr);
10561153
off = addr - chunk->base_addr;
10571154

1058-
pcpu_free_area(chunk, off);
1155+
pcpu_free_area(chunk, off, &occ_pages);
1156+
1157+
if (chunk != pcpu_reserved_chunk)
1158+
pcpu_nr_empty_pop_pages += occ_pages;
10591159

10601160
/* if there are more than one fully free chunks, wake up grim reaper */
10611161
if (chunk->free_size == pcpu_unit_size) {
@@ -1459,6 +1559,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
14591559
schunk->map_alloc = ARRAY_SIZE(smap);
14601560
schunk->immutable = true;
14611561
bitmap_fill(schunk->populated, pcpu_unit_pages);
1562+
schunk->nr_populated = pcpu_unit_pages;
14621563

14631564
if (ai->reserved_size) {
14641565
schunk->free_size = ai->reserved_size;
@@ -1488,6 +1589,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
14881589
dchunk->map_alloc = ARRAY_SIZE(dmap);
14891590
dchunk->immutable = true;
14901591
bitmap_fill(dchunk->populated, pcpu_unit_pages);
1592+
dchunk->nr_populated = pcpu_unit_pages;
14911593

14921594
dchunk->contig_hint = dchunk->free_size = dyn_size;
14931595
dchunk->map[0] = 1;
@@ -1498,6 +1600,8 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
14981600

14991601
/* link the first chunk in */
15001602
pcpu_first_chunk = dchunk ?: schunk;
1603+
pcpu_nr_empty_pop_pages +=
1604+
pcpu_count_occupied_pages(pcpu_first_chunk, 1);
15011605
pcpu_chunk_relocate(pcpu_first_chunk, -1);
15021606

15031607
/* we're done */

0 commit comments

Comments
 (0)