diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-25 18:50:53 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-25 18:50:53 -0400 |
| commit | 4b97280675f45c1650ee4e388bd711ecbb18c4b4 (patch) | |
| tree | 45f9de3f355ac9245b9bda38e61204725cc7d991 | |
| parent | e93dd910b906d2bb881f334685eb03431fd3fa48 (diff) | |
| parent | 15a3eac0784edb73cb2ec0f0c97705ba4bd39b3f (diff) | |
Merge tag 'stable/for-linus-3.12-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull Xen fixes from Konrad Rzeszutek Wilk:
"Bug-fixes and one update to the kernel-paramters.txt documentation.
- Fix PV spinlocks triggering jump_label code bug
- Remove extraneous code in the tpm front driver
- Fix ballooning out of pages when non-preemptible
- Fix deadlock when using a 32-bit initial domain with large amount
of memory
- Add xen_nopvpsin parameter to the documentation"
* tag 'stable/for-linus-3.12-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
xen/spinlock: Document the xen_nopvspin parameter.
xen/p2m: check MFN is in range before using the m2p table
xen/balloon: don't alloc page while non-preemptible
xen: Do not enable spinlocks before jump_label_init() has executed
tpm: xen-tpmfront: Remove the locality sysfs attribute
tpm: xen-tpmfront: Fix default durations
| -rw-r--r-- | Documentation/kernel-parameters.txt | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/xen/page.h | 31 | ||||
| -rw-r--r-- | arch/x86/xen/p2m.c | 10 | ||||
| -rw-r--r-- | arch/x86/xen/spinlock.c | 26 | ||||
| -rw-r--r-- | drivers/char/tpm/xen-tpmfront.c | 36 | ||||
| -rw-r--r-- | drivers/xen/balloon.c | 23 |
6 files changed, 63 insertions, 67 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1a036cd972fb..539a23631990 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -3485,6 +3485,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 3485 | the unplug protocol | 3485 | the unplug protocol |
| 3486 | never -- do not unplug even if version check succeeds | 3486 | never -- do not unplug even if version check succeeds |
| 3487 | 3487 | ||
| 3488 | xen_nopvspin [X86,XEN] | ||
| 3489 | Disables the ticketlock slowpath using Xen PV | ||
| 3490 | optimizations. | ||
| 3491 | |||
| 3488 | xirc2ps_cs= [NET,PCMCIA] | 3492 | xirc2ps_cs= [NET,PCMCIA] |
| 3489 | Format: | 3493 | Format: |
| 3490 | <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]] | 3494 | <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]] |
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 6aef9fbc09b7..b913915e8e63 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h | |||
| @@ -79,30 +79,38 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn) | |||
| 79 | return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY; | 79 | return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static inline unsigned long mfn_to_pfn(unsigned long mfn) | 82 | static inline unsigned long mfn_to_pfn_no_overrides(unsigned long mfn) |
| 83 | { | 83 | { |
| 84 | unsigned long pfn; | 84 | unsigned long pfn; |
| 85 | int ret = 0; | 85 | int ret; |
| 86 | 86 | ||
| 87 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 87 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
| 88 | return mfn; | 88 | return mfn; |
| 89 | 89 | ||
| 90 | if (unlikely(mfn >= machine_to_phys_nr)) { | 90 | if (unlikely(mfn >= machine_to_phys_nr)) |
| 91 | pfn = ~0; | 91 | return ~0; |
| 92 | goto try_override; | 92 | |
| 93 | } | ||
| 94 | pfn = 0; | ||
| 95 | /* | 93 | /* |
| 96 | * The array access can fail (e.g., device space beyond end of RAM). | 94 | * The array access can fail (e.g., device space beyond end of RAM). |
| 97 | * In such cases it doesn't matter what we return (we return garbage), | 95 | * In such cases it doesn't matter what we return (we return garbage), |
| 98 | * but we must handle the fault without crashing! | 96 | * but we must handle the fault without crashing! |
| 99 | */ | 97 | */ |
| 100 | ret = __get_user(pfn, &machine_to_phys_mapping[mfn]); | 98 | ret = __get_user(pfn, &machine_to_phys_mapping[mfn]); |
| 101 | try_override: | ||
| 102 | /* ret might be < 0 if there are no entries in the m2p for mfn */ | ||
| 103 | if (ret < 0) | 99 | if (ret < 0) |
| 104 | pfn = ~0; | 100 | return ~0; |
| 105 | else if (get_phys_to_machine(pfn) != mfn) | 101 | |
| 102 | return pfn; | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline unsigned long mfn_to_pfn(unsigned long mfn) | ||
| 106 | { | ||
| 107 | unsigned long pfn; | ||
| 108 | |||
| 109 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
| 110 | return mfn; | ||
| 111 | |||
| 112 | pfn = mfn_to_pfn_no_overrides(mfn); | ||
| 113 | if (get_phys_to_machine(pfn) != mfn) { | ||
| 106 | /* | 114 | /* |
| 107 | * If this appears to be a foreign mfn (because the pfn | 115 | * If this appears to be a foreign mfn (because the pfn |
| 108 | * doesn't map back to the mfn), then check the local override | 116 | * doesn't map back to the mfn), then check the local override |
| @@ -111,6 +119,7 @@ try_override: | |||
| 111 | * m2p_find_override_pfn returns ~0 if it doesn't find anything. | 119 | * m2p_find_override_pfn returns ~0 if it doesn't find anything. |
| 112 | */ | 120 | */ |
| 113 | pfn = m2p_find_override_pfn(mfn, ~0); | 121 | pfn = m2p_find_override_pfn(mfn, ~0); |
| 122 | } | ||
| 114 | 123 | ||
| 115 | /* | 124 | /* |
| 116 | * pfn is ~0 if there are no entries in the m2p for mfn or if the | 125 | * pfn is ~0 if there are no entries in the m2p for mfn or if the |
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 8b901e8d782d..a61c7d5811be 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c | |||
| @@ -879,7 +879,6 @@ int m2p_add_override(unsigned long mfn, struct page *page, | |||
| 879 | unsigned long uninitialized_var(address); | 879 | unsigned long uninitialized_var(address); |
| 880 | unsigned level; | 880 | unsigned level; |
| 881 | pte_t *ptep = NULL; | 881 | pte_t *ptep = NULL; |
| 882 | int ret = 0; | ||
| 883 | 882 | ||
| 884 | pfn = page_to_pfn(page); | 883 | pfn = page_to_pfn(page); |
| 885 | if (!PageHighMem(page)) { | 884 | if (!PageHighMem(page)) { |
| @@ -926,8 +925,8 @@ int m2p_add_override(unsigned long mfn, struct page *page, | |||
| 926 | * frontend pages while they are being shared with the backend, | 925 | * frontend pages while they are being shared with the backend, |
| 927 | * because mfn_to_pfn (that ends up being called by GUPF) will | 926 | * because mfn_to_pfn (that ends up being called by GUPF) will |
| 928 | * return the backend pfn rather than the frontend pfn. */ | 927 | * return the backend pfn rather than the frontend pfn. */ |
| 929 | ret = __get_user(pfn, &machine_to_phys_mapping[mfn]); | 928 | pfn = mfn_to_pfn_no_overrides(mfn); |
| 930 | if (ret == 0 && get_phys_to_machine(pfn) == mfn) | 929 | if (get_phys_to_machine(pfn) == mfn) |
| 931 | set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); | 930 | set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); |
| 932 | 931 | ||
| 933 | return 0; | 932 | return 0; |
| @@ -942,7 +941,6 @@ int m2p_remove_override(struct page *page, | |||
| 942 | unsigned long uninitialized_var(address); | 941 | unsigned long uninitialized_var(address); |
| 943 | unsigned level; | 942 | unsigned level; |
| 944 | pte_t *ptep = NULL; | 943 | pte_t *ptep = NULL; |
| 945 | int ret = 0; | ||
| 946 | 944 | ||
| 947 | pfn = page_to_pfn(page); | 945 | pfn = page_to_pfn(page); |
| 948 | mfn = get_phys_to_machine(pfn); | 946 | mfn = get_phys_to_machine(pfn); |
| @@ -1029,8 +1027,8 @@ int m2p_remove_override(struct page *page, | |||
| 1029 | * the original pfn causes mfn_to_pfn(mfn) to return the frontend | 1027 | * the original pfn causes mfn_to_pfn(mfn) to return the frontend |
| 1030 | * pfn again. */ | 1028 | * pfn again. */ |
| 1031 | mfn &= ~FOREIGN_FRAME_BIT; | 1029 | mfn &= ~FOREIGN_FRAME_BIT; |
| 1032 | ret = __get_user(pfn, &machine_to_phys_mapping[mfn]); | 1030 | pfn = mfn_to_pfn_no_overrides(mfn); |
| 1033 | if (ret == 0 && get_phys_to_machine(pfn) == FOREIGN_FRAME(mfn) && | 1031 | if (get_phys_to_machine(pfn) == FOREIGN_FRAME(mfn) && |
| 1034 | m2p_find_override(mfn) == NULL) | 1032 | m2p_find_override(mfn) == NULL) |
| 1035 | set_phys_to_machine(pfn, mfn); | 1033 | set_phys_to_machine(pfn, mfn); |
| 1036 | 1034 | ||
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index 253f63fceea1..be6b86078957 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c | |||
| @@ -259,6 +259,14 @@ void xen_uninit_lock_cpu(int cpu) | |||
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | 261 | ||
| 262 | /* | ||
| 263 | * Our init of PV spinlocks is split in two init functions due to us | ||
| 264 | * using paravirt patching and jump labels patching and having to do | ||
| 265 | * all of this before SMP code is invoked. | ||
| 266 | * | ||
| 267 | * The paravirt patching needs to be done _before_ the alternative asm code | ||
| 268 | * is started, otherwise we would not patch the core kernel code. | ||
| 269 | */ | ||
| 262 | void __init xen_init_spinlocks(void) | 270 | void __init xen_init_spinlocks(void) |
| 263 | { | 271 | { |
| 264 | 272 | ||
| @@ -267,12 +275,26 @@ void __init xen_init_spinlocks(void) | |||
| 267 | return; | 275 | return; |
| 268 | } | 276 | } |
| 269 | 277 | ||
| 270 | static_key_slow_inc(¶virt_ticketlocks_enabled); | ||
| 271 | |||
| 272 | pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning); | 278 | pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning); |
| 273 | pv_lock_ops.unlock_kick = xen_unlock_kick; | 279 | pv_lock_ops.unlock_kick = xen_unlock_kick; |
| 274 | } | 280 | } |
| 275 | 281 | ||
| 282 | /* | ||
| 283 | * While the jump_label init code needs to happend _after_ the jump labels are | ||
| 284 | * enabled and before SMP is started. Hence we use pre-SMP initcall level | ||
| 285 | * init. We cannot do it in xen_init_spinlocks as that is done before | ||
| 286 | * jump labels are activated. | ||
| 287 | */ | ||
| 288 | static __init int xen_init_spinlocks_jump(void) | ||
| 289 | { | ||
| 290 | if (!xen_pvspin) | ||
| 291 | return 0; | ||
| 292 | |||
| 293 | static_key_slow_inc(¶virt_ticketlocks_enabled); | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | early_initcall(xen_init_spinlocks_jump); | ||
| 297 | |||
| 276 | static __init int xen_parse_nopvspin(char *arg) | 298 | static __init int xen_parse_nopvspin(char *arg) |
| 277 | { | 299 | { |
| 278 | xen_pvspin = false; | 300 | xen_pvspin = false; |
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 7a7929ba2658..06189e55b4e5 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c | |||
| @@ -142,32 +142,6 @@ static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
| 142 | return length; | 142 | return length; |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | ssize_t tpm_show_locality(struct device *dev, struct device_attribute *attr, | ||
| 146 | char *buf) | ||
| 147 | { | ||
| 148 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 149 | struct tpm_private *priv = TPM_VPRIV(chip); | ||
| 150 | u8 locality = priv->shr->locality; | ||
| 151 | |||
| 152 | return sprintf(buf, "%d\n", locality); | ||
| 153 | } | ||
| 154 | |||
| 155 | ssize_t tpm_store_locality(struct device *dev, struct device_attribute *attr, | ||
| 156 | const char *buf, size_t len) | ||
| 157 | { | ||
| 158 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
| 159 | struct tpm_private *priv = TPM_VPRIV(chip); | ||
| 160 | u8 val; | ||
| 161 | |||
| 162 | int rv = kstrtou8(buf, 0, &val); | ||
| 163 | if (rv) | ||
| 164 | return rv; | ||
| 165 | |||
| 166 | priv->shr->locality = val; | ||
| 167 | |||
| 168 | return len; | ||
| 169 | } | ||
| 170 | |||
| 171 | static const struct file_operations vtpm_ops = { | 145 | static const struct file_operations vtpm_ops = { |
| 172 | .owner = THIS_MODULE, | 146 | .owner = THIS_MODULE, |
| 173 | .llseek = no_llseek, | 147 | .llseek = no_llseek, |
| @@ -188,8 +162,6 @@ static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | |||
| 188 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | 162 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); |
| 189 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | 163 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); |
| 190 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | 164 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); |
| 191 | static DEVICE_ATTR(locality, S_IRUGO | S_IWUSR, tpm_show_locality, | ||
| 192 | tpm_store_locality); | ||
| 193 | 165 | ||
| 194 | static struct attribute *vtpm_attrs[] = { | 166 | static struct attribute *vtpm_attrs[] = { |
| 195 | &dev_attr_pubek.attr, | 167 | &dev_attr_pubek.attr, |
| @@ -202,7 +174,6 @@ static struct attribute *vtpm_attrs[] = { | |||
| 202 | &dev_attr_cancel.attr, | 174 | &dev_attr_cancel.attr, |
| 203 | &dev_attr_durations.attr, | 175 | &dev_attr_durations.attr, |
| 204 | &dev_attr_timeouts.attr, | 176 | &dev_attr_timeouts.attr, |
| 205 | &dev_attr_locality.attr, | ||
| 206 | NULL, | 177 | NULL, |
| 207 | }; | 178 | }; |
| 208 | 179 | ||
| @@ -210,8 +181,6 @@ static struct attribute_group vtpm_attr_grp = { | |||
| 210 | .attrs = vtpm_attrs, | 181 | .attrs = vtpm_attrs, |
| 211 | }; | 182 | }; |
| 212 | 183 | ||
| 213 | #define TPM_LONG_TIMEOUT (10 * 60 * HZ) | ||
| 214 | |||
| 215 | static const struct tpm_vendor_specific tpm_vtpm = { | 184 | static const struct tpm_vendor_specific tpm_vtpm = { |
| 216 | .status = vtpm_status, | 185 | .status = vtpm_status, |
| 217 | .recv = vtpm_recv, | 186 | .recv = vtpm_recv, |
| @@ -224,11 +193,6 @@ static const struct tpm_vendor_specific tpm_vtpm = { | |||
| 224 | .miscdev = { | 193 | .miscdev = { |
| 225 | .fops = &vtpm_ops, | 194 | .fops = &vtpm_ops, |
| 226 | }, | 195 | }, |
| 227 | .duration = { | ||
| 228 | TPM_LONG_TIMEOUT, | ||
| 229 | TPM_LONG_TIMEOUT, | ||
| 230 | TPM_LONG_TIMEOUT, | ||
| 231 | }, | ||
| 232 | }; | 196 | }; |
| 233 | 197 | ||
| 234 | static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) | 198 | static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) |
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index a50c6e3a7cc4..b232908a6192 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
| @@ -398,8 +398,6 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) | |||
| 398 | if (nr_pages > ARRAY_SIZE(frame_list)) | 398 | if (nr_pages > ARRAY_SIZE(frame_list)) |
| 399 | nr_pages = ARRAY_SIZE(frame_list); | 399 | nr_pages = ARRAY_SIZE(frame_list); |
| 400 | 400 | ||
| 401 | scratch_page = get_balloon_scratch_page(); | ||
| 402 | |||
| 403 | for (i = 0; i < nr_pages; i++) { | 401 | for (i = 0; i < nr_pages; i++) { |
| 404 | page = alloc_page(gfp); | 402 | page = alloc_page(gfp); |
| 405 | if (page == NULL) { | 403 | if (page == NULL) { |
| @@ -413,6 +411,12 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) | |||
| 413 | 411 | ||
| 414 | scrub_page(page); | 412 | scrub_page(page); |
| 415 | 413 | ||
| 414 | /* | ||
| 415 | * Ballooned out frames are effectively replaced with | ||
| 416 | * a scratch frame. Ensure direct mappings and the | ||
| 417 | * p2m are consistent. | ||
| 418 | */ | ||
| 419 | scratch_page = get_balloon_scratch_page(); | ||
| 416 | #ifdef CONFIG_XEN_HAVE_PVMMU | 420 | #ifdef CONFIG_XEN_HAVE_PVMMU |
| 417 | if (xen_pv_domain() && !PageHighMem(page)) { | 421 | if (xen_pv_domain() && !PageHighMem(page)) { |
| 418 | ret = HYPERVISOR_update_va_mapping( | 422 | ret = HYPERVISOR_update_va_mapping( |
| @@ -422,24 +426,19 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) | |||
| 422 | BUG_ON(ret); | 426 | BUG_ON(ret); |
| 423 | } | 427 | } |
| 424 | #endif | 428 | #endif |
| 425 | } | ||
| 426 | |||
| 427 | /* Ensure that ballooned highmem pages don't have kmaps. */ | ||
| 428 | kmap_flush_unused(); | ||
| 429 | flush_tlb_all(); | ||
| 430 | |||
| 431 | /* No more mappings: invalidate P2M and add to balloon. */ | ||
| 432 | for (i = 0; i < nr_pages; i++) { | ||
| 433 | pfn = mfn_to_pfn(frame_list[i]); | ||
| 434 | if (!xen_feature(XENFEAT_auto_translated_physmap)) { | 429 | if (!xen_feature(XENFEAT_auto_translated_physmap)) { |
| 435 | unsigned long p; | 430 | unsigned long p; |
| 436 | p = page_to_pfn(scratch_page); | 431 | p = page_to_pfn(scratch_page); |
| 437 | __set_phys_to_machine(pfn, pfn_to_mfn(p)); | 432 | __set_phys_to_machine(pfn, pfn_to_mfn(p)); |
| 438 | } | 433 | } |
| 434 | put_balloon_scratch_page(); | ||
| 435 | |||
| 439 | balloon_append(pfn_to_page(pfn)); | 436 | balloon_append(pfn_to_page(pfn)); |
| 440 | } | 437 | } |
| 441 | 438 | ||
| 442 | put_balloon_scratch_page(); | 439 | /* Ensure that ballooned highmem pages don't have kmaps. */ |
| 440 | kmap_flush_unused(); | ||
| 441 | flush_tlb_all(); | ||
| 443 | 442 | ||
| 444 | set_xen_guest_handle(reservation.extent_start, frame_list); | 443 | set_xen_guest_handle(reservation.extent_start, frame_list); |
| 445 | reservation.nr_extents = nr_pages; | 444 | reservation.nr_extents = nr_pages; |
