Merge branch 'for-4.7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu

Pull percpu fixes from Tejun Heo:
"While adding GFP_ATOMIC support to the percpu allocator, the
synchronization for the fast-path which doesn't require external
allocations was separated into pcpu_lock.

Unfortunately, it incorrectly decoupled async paths and percpu
chunks could get destroyed while still being operated on. This
contains two patches to fix the bug"

* 'for-4.7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu:
percpu: fix synchronization between synchronous map extension and chunk destruction
percpu: fix synchronization between chunk->map_extend_work and chunk destruction

+44 -29
+44 -29
mm/percpu.c
··· 112 112 int map_used; /* # of map entries used before the sentry */ 113 113 int map_alloc; /* # of map entries allocated */ 114 114 int *map; /* allocation map */ 115 - struct work_struct map_extend_work;/* async ->map[] extension */ 115 + struct list_head map_extend_list;/* on pcpu_map_extend_chunks */ 116 116 117 117 void *data; /* chunk data */ 118 118 int first_free; /* no free below this */ ··· 162 162 static int pcpu_reserved_chunk_limit; 163 163 164 164 static DEFINE_SPINLOCK(pcpu_lock); /* all internal data structures */ 165 - static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop */ 165 + static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop, map ext */ 166 166 167 167 static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */ 168 + 169 + /* chunks which need their map areas extended, protected by pcpu_lock */ 170 + static LIST_HEAD(pcpu_map_extend_chunks); 168 171 169 172 /* 170 173 * The number of empty populated pages, protected by pcpu_lock. The ··· 398 395 { 399 396 int margin, new_alloc; 400 397 398 + lockdep_assert_held(&pcpu_lock); 399 + 401 400 if (is_atomic) { 402 401 margin = 3; 403 402 404 403 if (chunk->map_alloc < 405 - chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW && 406 - pcpu_async_enabled) 407 - schedule_work(&chunk->map_extend_work); 404 + chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW) { 405 + if (list_empty(&chunk->map_extend_list)) { 406 + list_add_tail(&chunk->map_extend_list, 407 + &pcpu_map_extend_chunks); 408 + pcpu_schedule_balance_work(); 409 + } 410 + } 408 411 } else { 409 412 margin = PCPU_ATOMIC_MAP_MARGIN_HIGH; 410 413 } ··· 444 435 size_t old_size = 0, new_size = new_alloc * sizeof(new[0]); 445 436 unsigned long flags; 446 437 438 + lockdep_assert_held(&pcpu_alloc_mutex); 439 + 447 440 new = pcpu_mem_zalloc(new_size); 448 441 if (!new) 449 442 return -ENOMEM; ··· 476 465 pcpu_mem_free(new); 477 466 478 467 return 0; 479 - } 480 - 481 - static void pcpu_map_extend_workfn(struct work_struct *work) 482 - { 483 - struct pcpu_chunk *chunk = container_of(work, struct pcpu_chunk, 484 - map_extend_work); 485 - int new_alloc; 486 - 487 - spin_lock_irq(&pcpu_lock); 488 - new_alloc = pcpu_need_to_extend(chunk, false); 489 - spin_unlock_irq(&pcpu_lock); 490 - 491 - if (new_alloc) 492 - pcpu_extend_area_map(chunk, new_alloc); 493 468 } 494 469 495 470 /** ··· 737 740 chunk->map_used = 1; 738 741 739 742 INIT_LIST_HEAD(&chunk->list); 740 - INIT_WORK(&chunk->map_extend_work, pcpu_map_extend_workfn); 743 + INIT_LIST_HEAD(&chunk->map_extend_list); 741 744 chunk->free_size = pcpu_unit_size; 742 745 chunk->contig_hint = pcpu_unit_size; 743 746 ··· 892 895 return NULL; 893 896 } 894 897 898 + if (!is_atomic) 899 + mutex_lock(&pcpu_alloc_mutex); 900 + 895 901 spin_lock_irqsave(&pcpu_lock, flags); 896 902 897 903 /* serve reserved allocations from the reserved chunk if available */ ··· 967 967 if (is_atomic) 968 968 goto fail; 969 969 970 - mutex_lock(&pcpu_alloc_mutex); 971 - 972 970 if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) { 973 971 chunk = pcpu_create_chunk(); 974 972 if (!chunk) { 975 - mutex_unlock(&pcpu_alloc_mutex); 976 973 err = "failed to allocate new chunk"; 977 974 goto fail; 978 975 } ··· 980 983 spin_lock_irqsave(&pcpu_lock, flags); 981 984 } 982 985 983 - mutex_unlock(&pcpu_alloc_mutex); 984 986 goto restart; 985 987 986 988 area_found: ··· 988 992 /* populate if not all pages are already there */ 989 993 if (!is_atomic) { 990 994 int page_start, page_end, rs, re; 991 - 992 - mutex_lock(&pcpu_alloc_mutex); 993 995 994 996 page_start = PFN_DOWN(off); 995 997 page_end = PFN_UP(off + size); ··· 999 1005 1000 1006 spin_lock_irqsave(&pcpu_lock, flags); 1001 1007 if (ret) { 1002 - mutex_unlock(&pcpu_alloc_mutex); 1003 1008 pcpu_free_area(chunk, off, &occ_pages); 1004 1009 err = "failed to populate"; 1005 1010 goto fail_unlock; ··· 1038 1045 /* see the flag handling in pcpu_blance_workfn() */ 1039 1046 pcpu_atomic_alloc_failed = true; 1040 1047 pcpu_schedule_balance_work(); 1048 + } else { 1049 + mutex_unlock(&pcpu_alloc_mutex); 1041 1050 } 1042 1051 return NULL; 1043 1052 } ··· 1124 1129 if (chunk == list_first_entry(free_head, struct pcpu_chunk, list)) 1125 1130 continue; 1126 1131 1132 + list_del_init(&chunk->map_extend_list); 1127 1133 list_move(&chunk->list, &to_free); 1128 1134 } 1129 1135 ··· 1141 1145 } 1142 1146 pcpu_destroy_chunk(chunk); 1143 1147 } 1148 + 1149 + /* service chunks which requested async area map extension */ 1150 + do { 1151 + int new_alloc = 0; 1152 + 1153 + spin_lock_irq(&pcpu_lock); 1154 + 1155 + chunk = list_first_entry_or_null(&pcpu_map_extend_chunks, 1156 + struct pcpu_chunk, map_extend_list); 1157 + if (chunk) { 1158 + list_del_init(&chunk->map_extend_list); 1159 + new_alloc = pcpu_need_to_extend(chunk, false); 1160 + } 1161 + 1162 + spin_unlock_irq(&pcpu_lock); 1163 + 1164 + if (new_alloc) 1165 + pcpu_extend_area_map(chunk, new_alloc); 1166 + } while (chunk); 1144 1167 1145 1168 /* 1146 1169 * Ensure there are certain number of free populated pages for ··· 1659 1644 */ 1660 1645 schunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0); 1661 1646 INIT_LIST_HEAD(&schunk->list); 1662 - INIT_WORK(&schunk->map_extend_work, pcpu_map_extend_workfn); 1647 + INIT_LIST_HEAD(&schunk->map_extend_list); 1663 1648 schunk->base_addr = base_addr; 1664 1649 schunk->map = smap; 1665 1650 schunk->map_alloc = ARRAY_SIZE(smap); ··· 1688 1673 if (dyn_size) { 1689 1674 dchunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0); 1690 1675 INIT_LIST_HEAD(&dchunk->list); 1691 - INIT_WORK(&dchunk->map_extend_work, pcpu_map_extend_workfn); 1676 + INIT_LIST_HEAD(&dchunk->map_extend_list); 1692 1677 dchunk->base_addr = base_addr; 1693 1678 dchunk->map = dmap; 1694 1679 dchunk->map_alloc = ARRAY_SIZE(dmap);