Commit b32fc0a0629bf5894b35f33554c118aacfd0d1e2

Authored by Linus Torvalds

Merge branch 'upstream/jump-label-noearly' of git://git.kernel.org/pub/scm/linux…

…/kernel/git/jeremy/xen

* 'upstream/jump-label-noearly' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen:
  jump-label: initialize jump-label subsystem much earlier
  x86/jump_label: add arch_jump_label_transform_static()
  s390/jump-label: add arch_jump_label_transform_static()
  jump_label: add arch_jump_label_transform_static() to optimise non-live code updates
  sparc/jump_label: drop arch_jump_label_text_poke_early()
  x86/jump_label: drop arch_jump_label_text_poke_early()
  jump_label: if a key has already been initialized, don't nop it out
  stop_machine: make stop_machine safe and efficient to call early
  jump_label: use proper atomic_t initializer

Conflicts:
 - arch/x86/kernel/jump_label.c
	Added __init_or_module to arch_jump_label_text_poke_early vs
	removal of that function entirely
 - kernel/stop_machine.c
	same patch ("stop_machine: make stop_machine safe and efficient
	to call early") merged twice, with whitespace fix in one version

Showing 6 changed files Side-by-side Diff

arch/s390/kernel/jump_label.c
... ... @@ -18,27 +18,16 @@
18 18 } __packed;
19 19  
20 20 struct insn_args {
21   - unsigned long *target;
22   - struct insn *insn;
23   - ssize_t size;
  21 + struct jump_entry *entry;
  22 + enum jump_label_type type;
24 23 };
25 24  
26   -static int __arch_jump_label_transform(void *data)
  25 +static void __jump_label_transform(struct jump_entry *entry,
  26 + enum jump_label_type type)
27 27 {
28   - struct insn_args *args = data;
  28 + struct insn insn;
29 29 int rc;
30 30  
31   - rc = probe_kernel_write(args->target, args->insn, args->size);
32   - WARN_ON_ONCE(rc < 0);
33   - return 0;
34   -}
35   -
36   -void arch_jump_label_transform(struct jump_entry *entry,
37   - enum jump_label_type type)
38   -{
39   - struct insn_args args;
40   - struct insn insn;
41   -
42 31 if (type == JUMP_LABEL_ENABLE) {
43 32 /* brcl 15,offset */
44 33 insn.opcode = 0xc0f4;
45 34  
... ... @@ -49,11 +38,33 @@
49 38 insn.offset = 0;
50 39 }
51 40  
52   - args.target = (void *) entry->code;
53   - args.insn = &insn;
54   - args.size = JUMP_LABEL_NOP_SIZE;
  41 + rc = probe_kernel_write((void *)entry->code, &insn, JUMP_LABEL_NOP_SIZE);
  42 + WARN_ON_ONCE(rc < 0);
  43 +}
55 44  
56   - stop_machine(__arch_jump_label_transform, &args, NULL);
  45 +static int __sm_arch_jump_label_transform(void *data)
  46 +{
  47 + struct insn_args *args = data;
  48 +
  49 + __jump_label_transform(args->entry, args->type);
  50 + return 0;
  51 +}
  52 +
  53 +void arch_jump_label_transform(struct jump_entry *entry,
  54 + enum jump_label_type type)
  55 +{
  56 + struct insn_args args;
  57 +
  58 + args.entry = entry;
  59 + args.type = type;
  60 +
  61 + stop_machine(__sm_arch_jump_label_transform, &args, NULL);
  62 +}
  63 +
  64 +void arch_jump_label_transform_static(struct jump_entry *entry,
  65 + enum jump_label_type type)
  66 +{
  67 + __jump_label_transform(entry, type);
57 68 }
58 69  
59 70 #endif
arch/sparc/kernel/jump_label.c
... ... @@ -36,13 +36,5 @@
36 36 put_online_cpus();
37 37 }
38 38  
39   -void arch_jump_label_text_poke_early(jump_label_t addr)
40   -{
41   - u32 *insn_p = (u32 *) (unsigned long) addr;
42   -
43   - *insn_p = 0x01000000;
44   - flushi(insn_p);
45   -}
46   -
47 39 #endif
arch/x86/kernel/jump_label.c
... ... @@ -24,8 +24,9 @@
24 24 } __attribute__((packed));
25 25 };
26 26  
27   -void arch_jump_label_transform(struct jump_entry *entry,
28   - enum jump_label_type type)
  27 +static void __jump_label_transform(struct jump_entry *entry,
  28 + enum jump_label_type type,
  29 + void *(*poker)(void *, const void *, size_t))
29 30 {
30 31 union jump_code_union code;
31 32  
32 33  
33 34  
34 35  
... ... @@ -35,17 +36,24 @@
35 36 (entry->code + JUMP_LABEL_NOP_SIZE);
36 37 } else
37 38 memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
  39 +
  40 + (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
  41 +}
  42 +
  43 +void arch_jump_label_transform(struct jump_entry *entry,
  44 + enum jump_label_type type)
  45 +{
38 46 get_online_cpus();
39 47 mutex_lock(&text_mutex);
40   - text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
  48 + __jump_label_transform(entry, type, text_poke_smp);
41 49 mutex_unlock(&text_mutex);
42 50 put_online_cpus();
43 51 }
44 52  
45   -void __init_or_module arch_jump_label_text_poke_early(jump_label_t addr)
  53 +void arch_jump_label_transform_static(struct jump_entry *entry,
  54 + enum jump_label_type type)
46 55 {
47   - text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5],
48   - JUMP_LABEL_NOP_SIZE);
  56 + __jump_label_transform(entry, type, text_poke_early);
49 57 }
50 58  
51 59 #endif
include/linux/jump_label.h
... ... @@ -16,7 +16,7 @@
16 16  
17 17 # include <asm/jump_label.h>
18 18 # define HAVE_JUMP_LABEL
19   -#endif
  19 +#endif /* CC_HAVE_ASM_GOTO && CONFIG_JUMP_LABEL */
20 20  
21 21 enum jump_label_type {
22 22 JUMP_LABEL_DISABLE = 0,
23 23  
... ... @@ -28,9 +28,9 @@
28 28 #ifdef HAVE_JUMP_LABEL
29 29  
30 30 #ifdef CONFIG_MODULES
31   -#define JUMP_LABEL_INIT {{ 0 }, NULL, NULL}
  31 +#define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL, NULL}
32 32 #else
33   -#define JUMP_LABEL_INIT {{ 0 }, NULL}
  33 +#define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL}
34 34 #endif
35 35  
36 36 static __always_inline bool static_branch(struct jump_label_key *key)
37 37  
38 38  
... ... @@ -41,18 +41,20 @@
41 41 extern struct jump_entry __start___jump_table[];
42 42 extern struct jump_entry __stop___jump_table[];
43 43  
  44 +extern void jump_label_init(void);
44 45 extern void jump_label_lock(void);
45 46 extern void jump_label_unlock(void);
46 47 extern void arch_jump_label_transform(struct jump_entry *entry,
47   - enum jump_label_type type);
48   -extern void arch_jump_label_text_poke_early(jump_label_t addr);
  48 + enum jump_label_type type);
  49 +extern void arch_jump_label_transform_static(struct jump_entry *entry,
  50 + enum jump_label_type type);
49 51 extern int jump_label_text_reserved(void *start, void *end);
50 52 extern void jump_label_inc(struct jump_label_key *key);
51 53 extern void jump_label_dec(struct jump_label_key *key);
52 54 extern bool jump_label_enabled(struct jump_label_key *key);
53 55 extern void jump_label_apply_nops(struct module *mod);
54 56  
55   -#else
  57 +#else /* !HAVE_JUMP_LABEL */
56 58  
57 59 #include <linux/atomic.h>
58 60  
... ... @@ -62,6 +64,10 @@
62 64 atomic_t enabled;
63 65 };
64 66  
  67 +static __always_inline void jump_label_init(void)
  68 +{
  69 +}
  70 +
65 71 static __always_inline bool static_branch(struct jump_label_key *key)
66 72 {
67 73 if (unlikely(atomic_read(&key->enabled)))
68 74  
... ... @@ -96,8 +102,7 @@
96 102 {
97 103 return 0;
98 104 }
  105 +#endif /* HAVE_JUMP_LABEL */
99 106  
100   -#endif
101   -
102   -#endif
  107 +#endif /* _LINUX_JUMP_LABEL_H */
... ... @@ -512,6 +512,9 @@
512 512 parse_args("Booting kernel", static_command_line, __start___param,
513 513 __stop___param - __start___param,
514 514 &unknown_bootoption);
  515 +
  516 + jump_label_init();
  517 +
515 518 /*
516 519 * These use large bootmem allocations and must precede
517 520 * kmem_cache_init()
... ... @@ -104,6 +104,18 @@
104 104 return 0;
105 105 }
106 106  
  107 +/*
  108 + * Update code which is definitely not currently executing.
  109 + * Architectures which need heavyweight synchronization to modify
  110 + * running code can override this to make the non-live update case
  111 + * cheaper.
  112 + */
  113 +void __weak arch_jump_label_transform_static(struct jump_entry *entry,
  114 + enum jump_label_type type)
  115 +{
  116 + arch_jump_label_transform(entry, type);
  117 +}
  118 +
107 119 static void __jump_label_update(struct jump_label_key *key,
108 120 struct jump_entry *entry,
109 121 struct jump_entry *stop, int enable)
110 122  
... ... @@ -121,15 +133,8 @@
121 133 }
122 134 }
123 135  
124   -/*
125   - * Not all archs need this.
126   - */
127   -void __weak arch_jump_label_text_poke_early(jump_label_t addr)
  136 +void __init jump_label_init(void)
128 137 {
129   -}
130   -
131   -static __init int jump_label_init(void)
132   -{
133 138 struct jump_entry *iter_start = __start___jump_table;
134 139 struct jump_entry *iter_stop = __stop___jump_table;
135 140 struct jump_label_key *key = NULL;
136 141  
137 142  
138 143  
... ... @@ -139,22 +144,22 @@
139 144 jump_label_sort_entries(iter_start, iter_stop);
140 145  
141 146 for (iter = iter_start; iter < iter_stop; iter++) {
142   - arch_jump_label_text_poke_early(iter->code);
143   - if (iter->key == (jump_label_t)(unsigned long)key)
  147 + struct jump_label_key *iterk;
  148 +
  149 + iterk = (struct jump_label_key *)(unsigned long)iter->key;
  150 + arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ?
  151 + JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE);
  152 + if (iterk == key)
144 153 continue;
145 154  
146   - key = (struct jump_label_key *)(unsigned long)iter->key;
147   - atomic_set(&key->enabled, 0);
  155 + key = iterk;
148 156 key->entries = iter;
149 157 #ifdef CONFIG_MODULES
150 158 key->next = NULL;
151 159 #endif
152 160 }
153 161 jump_label_unlock();
154   -
155   - return 0;
156 162 }
157   -early_initcall(jump_label_init);
158 163  
159 164 #ifdef CONFIG_MODULES
160 165  
... ... @@ -212,7 +217,7 @@
212 217 return;
213 218  
214 219 for (iter = iter_start; iter < iter_stop; iter++)
215   - arch_jump_label_text_poke_early(iter->code);
  220 + arch_jump_label_transform_static(iter, JUMP_LABEL_DISABLE);
216 221 }
217 222  
218 223 static int jump_label_add_module(struct module *mod)