/[linux-patches]/genpatches-2.6/tags/2.6.32-47/1032_linux-2.6.32.33.patch
Gentoo

Contents of /genpatches-2.6/tags/2.6.32-47/1032_linux-2.6.32.33.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2037 - (show annotations) (download)
Wed Dec 28 14:38:55 2011 UTC (6 years, 10 months ago) by psomas
File size: 16085 byte(s)
2.6.32-47 release
1 diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
2 index 6251a4b..c9dd94f 100644
3 --- a/arch/powerpc/include/asm/hvcall.h
4 +++ b/arch/powerpc/include/asm/hvcall.h
5 @@ -268,6 +268,7 @@ long plpar_hcall_raw(unsigned long opcode, unsigned long *retbuf, ...);
6 */
7 #define PLPAR_HCALL9_BUFSIZE 9
8 long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...);
9 +long plpar_hcall9_raw(unsigned long opcode, unsigned long *retbuf, ...);
10
11 /* For hcall instrumentation. One structure per-hcall, per-CPU */
12 struct hcall_stats {
13 diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
14 index 0a8439a..b779818 100644
15 --- a/arch/powerpc/kernel/crash.c
16 +++ b/arch/powerpc/kernel/crash.c
17 @@ -347,10 +347,12 @@ int crash_shutdown_unregister(crash_shutdown_t handler)
18 EXPORT_SYMBOL(crash_shutdown_unregister);
19
20 static unsigned long crash_shutdown_buf[JMP_BUF_LEN];
21 +static int crash_shutdown_cpu = -1;
22
23 static int handle_fault(struct pt_regs *regs)
24 {
25 - longjmp(crash_shutdown_buf, 1);
26 + if (crash_shutdown_cpu == smp_processor_id())
27 + longjmp(crash_shutdown_buf, 1);
28 return 0;
29 }
30
31 @@ -375,11 +377,14 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
32 for_each_irq(i) {
33 struct irq_desc *desc = irq_desc + i;
34
35 + if (!desc || !desc->chip || !desc->chip->eoi)
36 + continue;
37 +
38 if (desc->status & IRQ_INPROGRESS)
39 desc->chip->eoi(i);
40
41 if (!(desc->status & IRQ_DISABLED))
42 - desc->chip->disable(i);
43 + desc->chip->shutdown(i);
44 }
45
46 /*
47 @@ -388,6 +393,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
48 */
49 old_handler = __debugger_fault_handler;
50 __debugger_fault_handler = handle_fault;
51 + crash_shutdown_cpu = smp_processor_id();
52 for (i = 0; crash_shutdown_handles[i]; i++) {
53 if (setjmp(crash_shutdown_buf) == 0) {
54 /*
55 @@ -401,6 +407,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
56 asm volatile("sync; isync");
57 }
58 }
59 + crash_shutdown_cpu = -1;
60 __debugger_fault_handler = old_handler;
61
62 /*
63 diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
64 index 040bd1d..1a8de63 100644
65 --- a/arch/powerpc/kernel/machine_kexec_64.c
66 +++ b/arch/powerpc/kernel/machine_kexec_64.c
67 @@ -15,6 +15,7 @@
68 #include <linux/thread_info.h>
69 #include <linux/init_task.h>
70 #include <linux/errno.h>
71 +#include <linux/cpu.h>
72
73 #include <asm/page.h>
74 #include <asm/current.h>
75 @@ -169,10 +170,34 @@ static void kexec_smp_down(void *arg)
76 /* NOTREACHED */
77 }
78
79 +/*
80 + * We need to make sure each present CPU is online. The next kernel will scan
81 + * the device tree and assume primary threads are online and query secondary
82 + * threads via RTAS to online them if required. If we don't online primary
83 + * threads, they will be stuck. However, we also online secondary threads as we
84 + * may be using 'cede offline'. In this case RTAS doesn't see the secondary
85 + * threads as offline -- and again, these CPUs will be stuck.
86 + *
87 + * So, we online all CPUs that should be running, including secondary threads.
88 + */
89 +static void wake_offline_cpus(void)
90 +{
91 + int cpu = 0;
92 +
93 + for_each_present_cpu(cpu) {
94 + if (!cpu_online(cpu)) {
95 + printk(KERN_INFO "kexec: Waking offline cpu %d.\n",
96 + cpu);
97 + cpu_up(cpu);
98 + }
99 + }
100 +}
101 +
102 static void kexec_prepare_cpus(void)
103 {
104 int my_cpu, i, notified=-1;
105
106 + wake_offline_cpus();
107 smp_call_function(kexec_smp_down, NULL, /* wait */0);
108 my_cpu = get_cpu();
109
110 diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
111 index 04f638d..00d3b65 100644
112 --- a/arch/powerpc/kernel/setup_64.c
113 +++ b/arch/powerpc/kernel/setup_64.c
114 @@ -432,9 +432,18 @@ void __init setup_system(void)
115 DBG(" <- setup_system()\n");
116 }
117
118 +static u64 slb0_limit(void)
119 +{
120 + if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
121 + return 1UL << SID_SHIFT_1T;
122 + }
123 + return 1UL << SID_SHIFT;
124 +}
125 +
126 #ifdef CONFIG_IRQSTACKS
127 static void __init irqstack_early_init(void)
128 {
129 + u64 limit = slb0_limit();
130 unsigned int i;
131
132 /*
133 @@ -444,10 +453,10 @@ static void __init irqstack_early_init(void)
134 for_each_possible_cpu(i) {
135 softirq_ctx[i] = (struct thread_info *)
136 __va(lmb_alloc_base(THREAD_SIZE,
137 - THREAD_SIZE, 0x10000000));
138 + THREAD_SIZE, limit));
139 hardirq_ctx[i] = (struct thread_info *)
140 __va(lmb_alloc_base(THREAD_SIZE,
141 - THREAD_SIZE, 0x10000000));
142 + THREAD_SIZE, limit));
143 }
144 }
145 #else
146 @@ -478,7 +487,7 @@ static void __init exc_lvl_early_init(void)
147 */
148 static void __init emergency_stack_init(void)
149 {
150 - unsigned long limit;
151 + u64 limit;
152 unsigned int i;
153
154 /*
155 @@ -490,7 +499,7 @@ static void __init emergency_stack_init(void)
156 * bringup, we need to get at them in real mode. This means they
157 * must also be within the RMO region.
158 */
159 - limit = min(0x10000000ULL, lmb.rmo_size);
160 + limit = min(slb0_limit(), lmb.rmo_size);
161
162 for_each_possible_cpu(i) {
163 unsigned long sp;
164 diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S
165 index c1427b3..34c76a52 100644
166 --- a/arch/powerpc/platforms/pseries/hvCall.S
167 +++ b/arch/powerpc/platforms/pseries/hvCall.S
168 @@ -202,3 +202,41 @@ _GLOBAL(plpar_hcall9)
169 mtcrf 0xff,r0
170
171 blr /* return r3 = status */
172 +
173 +/* See plpar_hcall_raw to see why this is needed */
174 +_GLOBAL(plpar_hcall9_raw)
175 + HMT_MEDIUM
176 +
177 + mfcr r0
178 + stw r0,8(r1)
179 +
180 + std r4,STK_PARM(r4)(r1) /* Save ret buffer */
181 +
182 + mr r4,r5
183 + mr r5,r6
184 + mr r6,r7
185 + mr r7,r8
186 + mr r8,r9
187 + mr r9,r10
188 + ld r10,STK_PARM(r11)(r1) /* put arg7 in R10 */
189 + ld r11,STK_PARM(r12)(r1) /* put arg8 in R11 */
190 + ld r12,STK_PARM(r13)(r1) /* put arg9 in R12 */
191 +
192 + HVSC /* invoke the hypervisor */
193 +
194 + mr r0,r12
195 + ld r12,STK_PARM(r4)(r1)
196 + std r4, 0(r12)
197 + std r5, 8(r12)
198 + std r6, 16(r12)
199 + std r7, 24(r12)
200 + std r8, 32(r12)
201 + std r9, 40(r12)
202 + std r10,48(r12)
203 + std r11,56(r12)
204 + std r0, 64(r12)
205 +
206 + lwz r0,8(r1)
207 + mtcrf 0xff,r0
208 +
209 + blr /* return r3 = status */
210 diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
211 index 903eb9e..5f2c511 100644
212 --- a/arch/powerpc/platforms/pseries/lpar.c
213 +++ b/arch/powerpc/platforms/pseries/lpar.c
214 @@ -366,21 +366,28 @@ static void pSeries_lpar_hptab_clear(void)
215 {
216 unsigned long size_bytes = 1UL << ppc64_pft_size;
217 unsigned long hpte_count = size_bytes >> 4;
218 - unsigned long dummy1, dummy2, dword0;
219 + struct {
220 + unsigned long pteh;
221 + unsigned long ptel;
222 + } ptes[4];
223 long lpar_rc;
224 - int i;
225 + int i, j;
226
227 - /* TODO: Use bulk call */
228 - for (i = 0; i < hpte_count; i++) {
229 - /* dont remove HPTEs with VRMA mappings */
230 - lpar_rc = plpar_pte_remove_raw(H_ANDCOND, i, HPTE_V_1TB_SEG,
231 - &dummy1, &dummy2);
232 - if (lpar_rc == H_NOT_FOUND) {
233 - lpar_rc = plpar_pte_read_raw(0, i, &dword0, &dummy1);
234 - if (!lpar_rc && ((dword0 & HPTE_V_VRMA_MASK)
235 - != HPTE_V_VRMA_MASK))
236 - /* Can be hpte for 1TB Seg. So remove it */
237 - plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2);
238 + /* Read in batches of 4,
239 + * invalidate only valid entries not in the VRMA
240 + * hpte_count will be a multiple of 4
241 + */
242 + for (i = 0; i < hpte_count; i += 4) {
243 + lpar_rc = plpar_pte_read_4_raw(0, i, (void *)ptes);
244 + if (lpar_rc != H_SUCCESS)
245 + continue;
246 + for (j = 0; j < 4; j++){
247 + if ((ptes[j].pteh & HPTE_V_VRMA_MASK) ==
248 + HPTE_V_VRMA_MASK)
249 + continue;
250 + if (ptes[j].pteh & HPTE_V_VALID)
251 + plpar_pte_remove_raw(0, i + j, 0,
252 + &(ptes[j].pteh), &(ptes[j].ptel));
253 }
254 }
255 }
256 diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
257 index 45f634c..98d4256 100644
258 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
259 +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
260 @@ -169,6 +169,24 @@ static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
261 return rc;
262 }
263
264 +/*
265 + * plpar_pte_read_4_raw can be called in real mode.
266 + * ptes must be 8*sizeof(unsigned long)
267 + */
268 +static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
269 + unsigned long *ptes)
270 +
271 +{
272 + long rc;
273 + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
274 +
275 + rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
276 +
277 + memcpy(ptes, retbuf, 8*sizeof(unsigned long));
278 +
279 + return rc;
280 +}
281 +
282 static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
283 unsigned long avpn)
284 {
285 diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
286 index 20db37e..a550d37 100644
287 --- a/drivers/net/ixgbe/ixgbe_main.c
288 +++ b/drivers/net/ixgbe/ixgbe_main.c
289 @@ -2134,6 +2134,10 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
290 /* Decide whether to use packet split mode or not */
291 adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
292
293 + /* Disable packet split due to 82599 erratum #45 */
294 + if (hw->mac.type == ixgbe_mac_82599EB)
295 + adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
296 +
297 /* Set the RX buffer length according to the mode */
298 if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
299 rx_buf_len = IXGBE_RX_HDR_SIZE;
300 diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
301 index 7022b1b..3ebe50c 100644
302 --- a/drivers/net/r8169.c
303 +++ b/drivers/net/r8169.c
304 @@ -3741,7 +3741,8 @@ static void rtl_hw_start_8168(struct net_device *dev)
305 RTL_W16(IntrMitigate, 0x5151);
306
307 /* Work around for RxFIFO overflow. */
308 - if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
309 + if (tp->mac_version == RTL_GIGA_MAC_VER_11 ||
310 + tp->mac_version == RTL_GIGA_MAC_VER_22) {
311 tp->intr_event |= RxFIFOOver | PCSTimeout;
312 tp->intr_event &= ~RxOverflow;
313 }
314 @@ -4633,7 +4634,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
315
316 /* Work around for rx fifo overflow */
317 if (unlikely(status & RxFIFOOver) &&
318 - (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
319 + (tp->mac_version == RTL_GIGA_MAC_VER_11 ||
320 + tp->mac_version == RTL_GIGA_MAC_VER_22)) {
321 netif_stop_queue(dev);
322 rtl8169_tx_timeout(dev);
323 break;
324 diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
325 index cee4d4e..1160fca 100644
326 --- a/drivers/s390/char/keyboard.c
327 +++ b/drivers/s390/char/keyboard.c
328 @@ -462,7 +462,8 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file,
329 unsigned int cmd, unsigned long arg)
330 {
331 void __user *argp;
332 - int ct, perm;
333 + unsigned int ct;
334 + int perm;
335
336 argp = (void __user *)arg;
337
338 diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
339 index 59a6106..1d6385a 100644
340 --- a/drivers/staging/comedi/drivers/jr3_pci.c
341 +++ b/drivers/staging/comedi/drivers/jr3_pci.c
342 @@ -856,8 +856,11 @@ static int jr3_pci_attach(struct comedi_device *dev,
343 }
344
345 devpriv->pci_enabled = 1;
346 - devpriv->iobase =
347 - ioremap(pci_resource_start(card, 0), sizeof(struct jr3_t));
348 + devpriv->iobase = ioremap(pci_resource_start(card, 0),
349 + offsetof(struct jr3_t, channel[devpriv->n_channels]));
350 + if (!devpriv->iobase)
351 + return -ENOMEM;
352 +
353 result = alloc_subdevices(dev, devpriv->n_channels);
354 if (result < 0)
355 goto out;
356 diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
357 index e5bab6e..4fde2c5 100644
358 --- a/fs/nfsd/nfs4xdr.c
359 +++ b/fs/nfsd/nfs4xdr.c
360 @@ -1114,7 +1114,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
361
362 u32 dummy;
363 char *machine_name;
364 - int i;
365 + int i, j;
366 int nr_secflavs;
367
368 READ_BUF(16);
369 @@ -1187,7 +1187,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
370 READ_BUF(4);
371 READ32(dummy);
372 READ_BUF(dummy * 4);
373 - for (i = 0; i < dummy; ++i)
374 + for (j = 0; j < dummy; ++j)
375 READ32(dummy);
376 break;
377 case RPC_AUTH_GSS:
378 diff --git a/include/keys/rxrpc-type.h b/include/keys/rxrpc-type.h
379 index 5cb86c3..fc48754 100644
380 --- a/include/keys/rxrpc-type.h
381 +++ b/include/keys/rxrpc-type.h
382 @@ -99,7 +99,6 @@ struct rxrpc_key_token {
383 * structure of raw payloads passed to add_key() or instantiate key
384 */
385 struct rxrpc_key_data_v1 {
386 - u32 kif_version; /* 1 */
387 u16 security_index;
388 u16 ticket_length;
389 u32 expiry; /* time_t */
390 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
391 index ec12f8c..c27a182 100644
392 --- a/include/linux/netdevice.h
393 +++ b/include/linux/netdevice.h
394 @@ -2015,6 +2015,10 @@ static inline u32 dev_ethtool_get_flags(struct net_device *dev)
395 return 0;
396 return dev->ethtool_ops->get_flags(dev);
397 }
398 +
399 +#define MODULE_ALIAS_NETDEV(device) \
400 + MODULE_ALIAS("netdev-" device)
401 +
402 #endif /* __KERNEL__ */
403
404 #endif /* _LINUX_NETDEVICE_H */
405 diff --git a/kernel/cpuset.c b/kernel/cpuset.c
406 index b120fd0..d091ed3 100644
407 --- a/kernel/cpuset.c
408 +++ b/kernel/cpuset.c
409 @@ -1514,8 +1514,10 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
410 return -ENODEV;
411
412 trialcs = alloc_trial_cpuset(cs);
413 - if (!trialcs)
414 - return -ENOMEM;
415 + if (!trialcs) {
416 + retval = -ENOMEM;
417 + goto out;
418 + }
419
420 switch (cft->private) {
421 case FILE_CPULIST:
422 @@ -1530,6 +1532,7 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
423 }
424
425 free_trial_cpuset(trialcs);
426 +out:
427 cgroup_unlock();
428 return retval;
429 }
430 diff --git a/mm/mremap.c b/mm/mremap.c
431 index 8451908..166b824 100644
432 --- a/mm/mremap.c
433 +++ b/mm/mremap.c
434 @@ -92,9 +92,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
435 */
436 mapping = vma->vm_file->f_mapping;
437 spin_lock(&mapping->i_mmap_lock);
438 - if (new_vma->vm_truncate_count &&
439 - new_vma->vm_truncate_count != vma->vm_truncate_count)
440 - new_vma->vm_truncate_count = 0;
441 + new_vma->vm_truncate_count = 0;
442 }
443
444 /*
445 diff --git a/net/core/dev.c b/net/core/dev.c
446 index fd4c1e7..49e3782 100644
447 --- a/net/core/dev.c
448 +++ b/net/core/dev.c
449 @@ -1037,13 +1037,21 @@ EXPORT_SYMBOL(netdev_bonding_change);
450 void dev_load(struct net *net, const char *name)
451 {
452 struct net_device *dev;
453 + int no_module;
454
455 read_lock(&dev_base_lock);
456 dev = __dev_get_by_name(net, name);
457 read_unlock(&dev_base_lock);
458
459 - if (!dev && capable(CAP_NET_ADMIN))
460 - request_module("%s", name);
461 + no_module = !dev;
462 + if (no_module && capable(CAP_NET_ADMIN))
463 + no_module = request_module("netdev-%s", name);
464 + if (no_module && capable(CAP_SYS_MODULE)) {
465 + if (!request_module("%s", name))
466 + pr_err("Loading kernel module for a network device "
467 +"with CAP_SYS_MODULE (deprecated). Use CAP_NET_ADMIN and alias netdev-%s "
468 +"instead\n", name);
469 + }
470 }
471 EXPORT_SYMBOL(dev_load);
472
473 diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
474 index 1433338..cfab9e4 100644
475 --- a/net/ipv4/ip_gre.c
476 +++ b/net/ipv4/ip_gre.c
477 @@ -1708,3 +1708,4 @@ module_exit(ipgre_fini);
478 MODULE_LICENSE("GPL");
479 MODULE_ALIAS_RTNL_LINK("gre");
480 MODULE_ALIAS_RTNL_LINK("gretap");
481 +MODULE_ALIAS_NETDEV("gre0");
482 diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
483 index ae40ed1..f37df1a 100644
484 --- a/net/ipv4/ipip.c
485 +++ b/net/ipv4/ipip.c
486 @@ -853,3 +853,4 @@ static void __exit ipip_fini(void)
487 module_init(ipip_init);
488 module_exit(ipip_fini);
489 MODULE_LICENSE("GPL");
490 +MODULE_ALIAS_NETDEV("tunl0");
491 diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
492 index c595bbe..9a95c82 100644
493 --- a/net/ipv6/ip6_tunnel.c
494 +++ b/net/ipv6/ip6_tunnel.c
495 @@ -56,6 +56,7 @@
496 MODULE_AUTHOR("Ville Nuorvala");
497 MODULE_DESCRIPTION("IPv6 tunneling device");
498 MODULE_LICENSE("GPL");
499 +MODULE_ALIAS_NETDEV("ip6tnl0");
500
501 #define IPV6_TLV_TEL_DST_SIZE 8
502
503 diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
504 index dbd19a7..de2ffef 100644
505 --- a/net/ipv6/sit.c
506 +++ b/net/ipv6/sit.c
507 @@ -1101,4 +1101,4 @@ static int __init sit_init(void)
508 module_init(sit_init);
509 module_exit(sit_cleanup);
510 MODULE_LICENSE("GPL");
511 -MODULE_ALIAS("sit0");
512 +MODULE_ALIAS_NETDEV("sit0");
513 diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
514 index d65d348..e54392e 100644
515 --- a/net/netfilter/nf_log.c
516 +++ b/net/netfilter/nf_log.c
517 @@ -83,6 +83,8 @@ EXPORT_SYMBOL(nf_log_unregister);
518
519 int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
520 {
521 + if (pf >= ARRAY_SIZE(nf_loggers))
522 + return -EINVAL;
523 mutex_lock(&nf_log_mutex);
524 if (__find_logger(pf, logger->name) == NULL) {
525 mutex_unlock(&nf_log_mutex);
526 @@ -96,6 +98,8 @@ EXPORT_SYMBOL(nf_log_bind_pf);
527
528 void nf_log_unbind_pf(u_int8_t pf)
529 {
530 + if (pf >= ARRAY_SIZE(nf_loggers))
531 + return;
532 mutex_lock(&nf_log_mutex);
533 rcu_assign_pointer(nf_loggers[pf], NULL);
534 mutex_unlock(&nf_log_mutex);

  ViewVC Help
Powered by ViewVC 1.1.20