| .. | .. |
|---|
| 6 | 6 | #include <linux/percpu.h> |
|---|
| 7 | 7 | |
|---|
| 8 | 8 | /* |
|---|
| 9 | + * There are two chunk types: root and memcg-aware. |
|---|
| 10 | + * Chunks of each type have separate slots list. |
|---|
| 11 | + * |
|---|
| 12 | + * Memcg-aware chunks have an attached vector of obj_cgroup pointers, which is |
|---|
| 13 | + * used to store memcg membership data of a percpu object. Obj_cgroups are |
|---|
| 14 | + * ref-counted pointers to a memory cgroup with an ability to switch dynamically |
|---|
| 15 | + * to the parent memory cgroup. This allows to reclaim a deleted memory cgroup |
|---|
| 16 | + * without reclaiming of all outstanding objects, which hold a reference at it. |
|---|
| 17 | + */ |
|---|
| 18 | +enum pcpu_chunk_type { |
|---|
| 19 | + PCPU_CHUNK_ROOT, |
|---|
| 20 | +#ifdef CONFIG_MEMCG_KMEM |
|---|
| 21 | + PCPU_CHUNK_MEMCG, |
|---|
| 22 | +#endif |
|---|
| 23 | + PCPU_NR_CHUNK_TYPES, |
|---|
| 24 | + PCPU_FAIL_ALLOC = PCPU_NR_CHUNK_TYPES |
|---|
| 25 | +}; |
|---|
| 26 | + |
|---|
| 27 | +/* |
|---|
| 9 | 28 | * pcpu_block_md is the metadata block struct. |
|---|
| 10 | 29 | * Each chunk's bitmap is split into a number of full blocks. |
|---|
| 11 | 30 | * All units are in terms of bits. |
|---|
| 31 | + * |
|---|
| 32 | + * The scan hint is the largest known contiguous area before the contig hint. |
|---|
| 33 | + * It is not necessarily the actual largest contig hint though. There is an |
|---|
| 34 | + * invariant that the scan_hint_start > contig_hint_start iff |
|---|
| 35 | + * scan_hint == contig_hint. This is necessary because when scanning forward, |
|---|
| 36 | + * we don't know if a new contig hint would be better than the current one. |
|---|
| 12 | 37 | */ |
|---|
| 13 | 38 | struct pcpu_block_md { |
|---|
| 39 | + int scan_hint; /* scan hint for block */ |
|---|
| 40 | + int scan_hint_start; /* block relative starting |
|---|
| 41 | + position of the scan hint */ |
|---|
| 14 | 42 | int contig_hint; /* contig hint for block */ |
|---|
| 15 | 43 | int contig_hint_start; /* block relative starting |
|---|
| 16 | 44 | position of the contig hint */ |
|---|
| .. | .. |
|---|
| 19 | 47 | int right_free; /* size of free space along |
|---|
| 20 | 48 | the right side of the block */ |
|---|
| 21 | 49 | int first_free; /* block position of first free */ |
|---|
| 50 | + int nr_bits; /* total bits responsible for */ |
|---|
| 22 | 51 | }; |
|---|
| 23 | 52 | |
|---|
| 24 | 53 | struct pcpu_chunk { |
|---|
| .. | .. |
|---|
| 29 | 58 | |
|---|
| 30 | 59 | struct list_head list; /* linked to pcpu_slot lists */ |
|---|
| 31 | 60 | int free_bytes; /* free bytes in the chunk */ |
|---|
| 32 | | - int contig_bits; /* max contiguous size hint */ |
|---|
| 33 | | - int contig_bits_start; /* contig_bits starting |
|---|
| 34 | | - offset */ |
|---|
| 61 | + struct pcpu_block_md chunk_md; |
|---|
| 35 | 62 | void *base_addr; /* base address of this chunk */ |
|---|
| 36 | 63 | |
|---|
| 37 | 64 | unsigned long *alloc_map; /* allocation map */ |
|---|
| .. | .. |
|---|
| 39 | 66 | struct pcpu_block_md *md_blocks; /* metadata blocks */ |
|---|
| 40 | 67 | |
|---|
| 41 | 68 | void *data; /* chunk data */ |
|---|
| 42 | | - int first_bit; /* no free below this */ |
|---|
| 43 | 69 | bool immutable; /* no [de]population allowed */ |
|---|
| 44 | 70 | int start_offset; /* the overlap with the previous |
|---|
| 45 | 71 | region to have a page aligned |
|---|
| .. | .. |
|---|
| 47 | 73 | int end_offset; /* additional area required to |
|---|
| 48 | 74 | have the region end page |
|---|
| 49 | 75 | aligned */ |
|---|
| 76 | +#ifdef CONFIG_MEMCG_KMEM |
|---|
| 77 | + struct obj_cgroup **obj_cgroups; /* vector of object cgroups */ |
|---|
| 78 | +#endif |
|---|
| 50 | 79 | |
|---|
| 51 | 80 | int nr_pages; /* # of pages served by this chunk */ |
|---|
| 52 | 81 | int nr_populated; /* # of populated pages */ |
|---|
| .. | .. |
|---|
| 56 | 85 | |
|---|
| 57 | 86 | extern spinlock_t pcpu_lock; |
|---|
| 58 | 87 | |
|---|
| 59 | | -extern struct list_head *pcpu_slot; |
|---|
| 88 | +extern struct list_head *pcpu_chunk_lists; |
|---|
| 60 | 89 | extern int pcpu_nr_slots; |
|---|
| 61 | | -extern int pcpu_nr_empty_pop_pages; |
|---|
| 90 | +extern int pcpu_nr_empty_pop_pages[]; |
|---|
| 62 | 91 | |
|---|
| 63 | 92 | extern struct pcpu_chunk *pcpu_first_chunk; |
|---|
| 64 | 93 | extern struct pcpu_chunk *pcpu_reserved_chunk; |
|---|
| .. | .. |
|---|
| 99 | 128 | return pcpu_nr_pages_to_map_bits(chunk->nr_pages); |
|---|
| 100 | 129 | } |
|---|
| 101 | 130 | |
|---|
| 131 | +#ifdef CONFIG_MEMCG_KMEM |
|---|
| 132 | +static inline enum pcpu_chunk_type pcpu_chunk_type(struct pcpu_chunk *chunk) |
|---|
| 133 | +{ |
|---|
| 134 | + if (chunk->obj_cgroups) |
|---|
| 135 | + return PCPU_CHUNK_MEMCG; |
|---|
| 136 | + return PCPU_CHUNK_ROOT; |
|---|
| 137 | +} |
|---|
| 138 | + |
|---|
| 139 | +static inline bool pcpu_is_memcg_chunk(enum pcpu_chunk_type chunk_type) |
|---|
| 140 | +{ |
|---|
| 141 | + return chunk_type == PCPU_CHUNK_MEMCG; |
|---|
| 142 | +} |
|---|
| 143 | + |
|---|
| 144 | +#else |
|---|
| 145 | +static inline enum pcpu_chunk_type pcpu_chunk_type(struct pcpu_chunk *chunk) |
|---|
| 146 | +{ |
|---|
| 147 | + return PCPU_CHUNK_ROOT; |
|---|
| 148 | +} |
|---|
| 149 | + |
|---|
| 150 | +static inline bool pcpu_is_memcg_chunk(enum pcpu_chunk_type chunk_type) |
|---|
| 151 | +{ |
|---|
| 152 | + return false; |
|---|
| 153 | +} |
|---|
| 154 | +#endif |
|---|
| 155 | + |
|---|
| 156 | +static inline struct list_head *pcpu_chunk_list(enum pcpu_chunk_type chunk_type) |
|---|
| 157 | +{ |
|---|
| 158 | + return &pcpu_chunk_lists[pcpu_nr_slots * |
|---|
| 159 | + pcpu_is_memcg_chunk(chunk_type)]; |
|---|
| 160 | +} |
|---|
| 161 | + |
|---|
| 102 | 162 | #ifdef CONFIG_PERCPU_STATS |
|---|
| 103 | 163 | |
|---|
| 104 | 164 | #include <linux/spinlock.h> |
|---|