From: Greg Kroah-Hartman Date: Wed, 17 Oct 2012 21:54:20 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.47~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6272dcedd68b512842b6e266c069dd48262a7e10;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: jbd-fix-assertion-failure-in-commit-code-due-to-lacking-transaction-credits.patch tpm-propagate-error-from-tpm_transmit-to-fix-a-timeout-hang.patch x86-random-architectural-inlines-to-get-random-integers-with-rdrand.patch x86-random-verify-rdrand-functionality-and-allow-it-to-be-disabled.patch --- diff --git a/queue-3.0/jbd-fix-assertion-failure-in-commit-code-due-to-lacking-transaction-credits.patch b/queue-3.0/jbd-fix-assertion-failure-in-commit-code-due-to-lacking-transaction-credits.patch new file mode 100644 index 00000000000..148e2180787 --- /dev/null +++ b/queue-3.0/jbd-fix-assertion-failure-in-commit-code-due-to-lacking-transaction-credits.patch @@ -0,0 +1,230 @@ +From 09e05d4805e6c524c1af74e524e5d0528bb3fef3 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 11 Jul 2012 23:16:25 +0200 +Subject: jbd: Fix assertion failure in commit code due to lacking transaction credits + +From: Jan Kara + +commit 09e05d4805e6c524c1af74e524e5d0528bb3fef3 upstream. + +ext3 users of data=journal mode with blocksize < pagesize were occasionally +hitting assertion failure in journal_commit_transaction() checking whether the +transaction has at least as many credits reserved as buffers attached. The +core of the problem is that when a file gets truncated, buffers that still need +checkpointing or that are attached to the committing transaction are left with +buffer_mapped set. When this happens to buffers beyond i_size attached to a +page stradding i_size, subsequent write extending the file will see these +buffers and as they are mapped (but underlying blocks were freed) things go +awry from here. + +The assertion failure just coincidentally (and in this case luckily as we would +start corrupting filesystem) triggers due to journal_head not being properly +cleaned up as well. + +Under some rare circumstances this bug could even hit data=ordered mode users. +There the assertion won't trigger and we would end up corrupting the +filesystem. + +We fix the problem by unmapping buffers if possible (in lots of cases we just +need a buffer attached to a transaction as a place holder but it must not be +written out anyway). And in one case, we just have to bite the bullet and wait +for transaction commit to finish. + +Reviewed-by: Josef Bacik +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + fs/jbd/commit.c | 45 +++++++++++++++++++++++++++-------- + fs/jbd/transaction.c | 64 +++++++++++++++++++++++++++++++++++---------------- + 2 files changed, 78 insertions(+), 31 deletions(-) + +--- a/fs/jbd/commit.c ++++ b/fs/jbd/commit.c +@@ -85,7 +85,12 @@ nope: + static void release_data_buffer(struct buffer_head *bh) + { + if (buffer_freed(bh)) { ++ WARN_ON_ONCE(buffer_dirty(bh)); + clear_buffer_freed(bh); ++ clear_buffer_mapped(bh); ++ clear_buffer_new(bh); ++ clear_buffer_req(bh); ++ bh->b_bdev = NULL; + release_buffer_page(bh); + } else + put_bh(bh); +@@ -840,17 +845,35 @@ restart_loop: + * there's no point in keeping a checkpoint record for + * it. */ + +- /* A buffer which has been freed while still being +- * journaled by a previous transaction may end up still +- * being dirty here, but we want to avoid writing back +- * that buffer in the future after the "add to orphan" +- * operation been committed, That's not only a performance +- * gain, it also stops aliasing problems if the buffer is +- * left behind for writeback and gets reallocated for another +- * use in a different page. */ +- if (buffer_freed(bh) && !jh->b_next_transaction) { +- clear_buffer_freed(bh); +- clear_buffer_jbddirty(bh); ++ /* ++ * A buffer which has been freed while still being journaled by ++ * a previous transaction. ++ */ ++ if (buffer_freed(bh)) { ++ /* ++ * If the running transaction is the one containing ++ * "add to orphan" operation (b_next_transaction != ++ * NULL), we have to wait for that transaction to ++ * commit before we can really get rid of the buffer. ++ * So just clear b_modified to not confuse transaction ++ * credit accounting and refile the buffer to ++ * BJ_Forget of the running transaction. If the just ++ * committed transaction contains "add to orphan" ++ * operation, we can completely invalidate the buffer ++ * now. We are rather throughout in that since the ++ * buffer may be still accessible when blocksize < ++ * pagesize and it is attached to the last partial ++ * page. ++ */ ++ jh->b_modified = 0; ++ if (!jh->b_next_transaction) { ++ clear_buffer_freed(bh); ++ clear_buffer_jbddirty(bh); ++ clear_buffer_mapped(bh); ++ clear_buffer_new(bh); ++ clear_buffer_req(bh); ++ bh->b_bdev = NULL; ++ } + } + + if (buffer_jbddirty(bh)) { +--- a/fs/jbd/transaction.c ++++ b/fs/jbd/transaction.c +@@ -1837,15 +1837,16 @@ static int __dispose_buffer(struct journ + * We're outside-transaction here. Either or both of j_running_transaction + * and j_committing_transaction may be NULL. + */ +-static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) ++static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, ++ int partial_page) + { + transaction_t *transaction; + struct journal_head *jh; + int may_free = 1; +- int ret; + + BUFFER_TRACE(bh, "entry"); + ++retry: + /* + * It is safe to proceed here without the j_list_lock because the + * buffers cannot be stolen by try_to_free_buffers as long as we are +@@ -1873,10 +1874,18 @@ static int journal_unmap_buffer(journal_ + * clear the buffer dirty bit at latest at the moment when the + * transaction marking the buffer as freed in the filesystem + * structures is committed because from that moment on the +- * buffer can be reallocated and used by a different page. ++ * block can be reallocated and used by a different page. + * Since the block hasn't been freed yet but the inode has + * already been added to orphan list, it is safe for us to add + * the buffer to BJ_Forget list of the newest transaction. ++ * ++ * Also we have to clear buffer_mapped flag of a truncated buffer ++ * because the buffer_head may be attached to the page straddling ++ * i_size (can happen only when blocksize < pagesize) and thus the ++ * buffer_head can be reused when the file is extended again. So we end ++ * up keeping around invalidated buffers attached to transactions' ++ * BJ_Forget list just to stop checkpointing code from cleaning up ++ * the transaction this buffer was modified in. + */ + transaction = jh->b_transaction; + if (transaction == NULL) { +@@ -1903,13 +1912,9 @@ static int journal_unmap_buffer(journal_ + * committed, the buffer won't be needed any + * longer. */ + JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); +- ret = __dispose_buffer(jh, ++ may_free = __dispose_buffer(jh, + journal->j_running_transaction); +- journal_put_journal_head(jh); +- spin_unlock(&journal->j_list_lock); +- jbd_unlock_bh_state(bh); +- spin_unlock(&journal->j_state_lock); +- return ret; ++ goto zap_buffer; + } else { + /* There is no currently-running transaction. So the + * orphan record which we wrote for this file must have +@@ -1917,13 +1922,9 @@ static int journal_unmap_buffer(journal_ + * the committing transaction, if it exists. */ + if (journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "give to committing trans"); +- ret = __dispose_buffer(jh, ++ may_free = __dispose_buffer(jh, + journal->j_committing_transaction); +- journal_put_journal_head(jh); +- spin_unlock(&journal->j_list_lock); +- jbd_unlock_bh_state(bh); +- spin_unlock(&journal->j_state_lock); +- return ret; ++ goto zap_buffer; + } else { + /* The orphan record's transaction has + * committed. We can cleanse this buffer */ +@@ -1944,10 +1945,24 @@ static int journal_unmap_buffer(journal_ + } + /* + * The buffer is committing, we simply cannot touch +- * it. So we just set j_next_transaction to the +- * running transaction (if there is one) and mark +- * buffer as freed so that commit code knows it should +- * clear dirty bits when it is done with the buffer. ++ * it. If the page is straddling i_size we have to wait ++ * for commit and try again. ++ */ ++ if (partial_page) { ++ tid_t tid = journal->j_committing_transaction->t_tid; ++ ++ journal_put_journal_head(jh); ++ spin_unlock(&journal->j_list_lock); ++ jbd_unlock_bh_state(bh); ++ spin_unlock(&journal->j_state_lock); ++ log_wait_commit(journal, tid); ++ goto retry; ++ } ++ /* ++ * OK, buffer won't be reachable after truncate. We just set ++ * j_next_transaction to the running transaction (if there is ++ * one) and mark buffer as freed so that commit code knows it ++ * should clear dirty bits when it is done with the buffer. + */ + set_buffer_freed(bh); + if (journal->j_running_transaction && buffer_jbddirty(bh)) +@@ -1970,6 +1985,14 @@ static int journal_unmap_buffer(journal_ + } + + zap_buffer: ++ /* ++ * This is tricky. Although the buffer is truncated, it may be reused ++ * if blocksize < pagesize and it is attached to the page straddling ++ * EOF. Since the buffer might have been added to BJ_Forget list of the ++ * running transaction, journal_get_write_access() won't clear ++ * b_modified and credit accounting gets confused. So clear b_modified ++ * here. */ ++ jh->b_modified = 0; + journal_put_journal_head(jh); + zap_buffer_no_jh: + spin_unlock(&journal->j_list_lock); +@@ -2018,7 +2041,8 @@ void journal_invalidatepage(journal_t *j + if (offset <= curr_off) { + /* This block is wholly outside the truncation point */ + lock_buffer(bh); +- may_free &= journal_unmap_buffer(journal, bh); ++ may_free &= journal_unmap_buffer(journal, bh, ++ offset > 0); + unlock_buffer(bh); + } + curr_off = next_off; diff --git a/queue-3.0/series b/queue-3.0/series index e172094fefd..faba33a5cb0 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -28,3 +28,7 @@ netfilter-limit-hashlimit-avoid-duplicated-inline.patch netfilter-xt_limit-have-r-cost-0-case-work.patch add-cdc-acm-support-for-the-cx93010-2x-ucmxx-usb-modem.patch drm-radeon-don-t-destroy-i2c-bus-rec-in-radeon_ext_tmds_enc_destroy.patch +jbd-fix-assertion-failure-in-commit-code-due-to-lacking-transaction-credits.patch +x86-random-architectural-inlines-to-get-random-integers-with-rdrand.patch +x86-random-verify-rdrand-functionality-and-allow-it-to-be-disabled.patch +tpm-propagate-error-from-tpm_transmit-to-fix-a-timeout-hang.patch diff --git a/queue-3.0/tpm-propagate-error-from-tpm_transmit-to-fix-a-timeout-hang.patch b/queue-3.0/tpm-propagate-error-from-tpm_transmit-to-fix-a-timeout-hang.patch new file mode 100644 index 00000000000..7bf216c0957 --- /dev/null +++ b/queue-3.0/tpm-propagate-error-from-tpm_transmit-to-fix-a-timeout-hang.patch @@ -0,0 +1,95 @@ +From abce9ac292e13da367bbd22c1f7669f988d931ac Mon Sep 17 00:00:00 2001 +From: Peter Huewe +Date: Thu, 27 Sep 2012 16:09:33 +0200 +Subject: tpm: Propagate error from tpm_transmit to fix a timeout hang + +From: Peter Huewe + +commit abce9ac292e13da367bbd22c1f7669f988d931ac upstream. + +tpm_write calls tpm_transmit without checking the return value and +assigns the return value unconditionally to chip->pending_data, even if +it's an error value. +This causes three bugs. + +So if we write to /dev/tpm0 with a tpm_param_size bigger than +TPM_BUFSIZE=0x1000 (e.g. 0x100a) +and a bufsize also bigger than TPM_BUFSIZE (e.g. 0x100a) +tpm_transmit returns -E2BIG which is assigned to chip->pending_data as +-7, but tpm_write returns that TPM_BUFSIZE bytes have been successfully +been written to the TPM, altough this is not true (bug #1). + +As we did write more than than TPM_BUFSIZE bytes but tpm_write reports +that only TPM_BUFSIZE bytes have been written the vfs tries to write +the remaining bytes (in this case 10 bytes) to the tpm device driver via +tpm_write which then blocks at + + /* cannot perform a write until the read has cleared + either via tpm_read or a user_read_timer timeout */ + while (atomic_read(&chip->data_pending) != 0) + msleep(TPM_TIMEOUT); + +for 60 seconds, since data_pending is -7 and nobody is able to +read it (since tpm_read luckily checks if data_pending is greater than +0) (#bug 2). + +After that the remaining bytes are written to the TPM which are +interpreted by the tpm as a normal command. (bug #3) +So if the last bytes of the command stream happen to be a e.g. +tpm_force_clear this gets accidentally sent to the TPM. + +This patch fixes all three bugs, by propagating the error code of +tpm_write and returning -E2BIG if the input buffer is too big, +since the response from the tpm for a truncated value is bogus anyway. +Moreover it returns -EBUSY to userspace if there is a response ready to be +read. + +Signed-off-by: Peter Huewe +Signed-off-by: Kent Yoder +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/char/tpm/tpm.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +--- a/drivers/char/tpm/tpm.c ++++ b/drivers/char/tpm/tpm.c +@@ -1019,17 +1019,20 @@ ssize_t tpm_write(struct file *file, con + size_t size, loff_t *off) + { + struct tpm_chip *chip = file->private_data; +- size_t in_size = size, out_size; ++ size_t in_size = size; ++ ssize_t out_size; + + /* cannot perform a write until the read has cleared +- either via tpm_read or a user_read_timer timeout */ +- while (atomic_read(&chip->data_pending) != 0) +- msleep(TPM_TIMEOUT); +- +- mutex_lock(&chip->buffer_mutex); ++ either via tpm_read or a user_read_timer timeout. ++ This also prevents splitted buffered writes from blocking here. ++ */ ++ if (atomic_read(&chip->data_pending) != 0) ++ return -EBUSY; + + if (in_size > TPM_BUFSIZE) +- in_size = TPM_BUFSIZE; ++ return -E2BIG; ++ ++ mutex_lock(&chip->buffer_mutex); + + if (copy_from_user + (chip->data_buffer, (void __user *) buf, in_size)) { +@@ -1039,6 +1042,10 @@ ssize_t tpm_write(struct file *file, con + + /* atomic tpm command send and result receive */ + out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); ++ if (out_size < 0) { ++ mutex_unlock(&chip->buffer_mutex); ++ return out_size; ++ } + + atomic_set(&chip->data_pending, out_size); + mutex_unlock(&chip->buffer_mutex); diff --git a/queue-3.0/x86-random-architectural-inlines-to-get-random-integers-with-rdrand.patch b/queue-3.0/x86-random-architectural-inlines-to-get-random-integers-with-rdrand.patch new file mode 100644 index 00000000000..18e04dedb57 --- /dev/null +++ b/queue-3.0/x86-random-architectural-inlines-to-get-random-integers-with-rdrand.patch @@ -0,0 +1,145 @@ +From 628c6246d47b85f5357298601df2444d7f4dd3fd Mon Sep 17 00:00:00 2001 +From: "H. Peter Anvin" +Date: Sun, 31 Jul 2011 13:59:29 -0700 +Subject: x86, random: Architectural inlines to get random integers with RDRAND + +From: "H. Peter Anvin" + +commit 628c6246d47b85f5357298601df2444d7f4dd3fd upstream. + +Architectural inlines to get random ints and longs using the RDRAND +instruction. + +Intel has introduced a new RDRAND instruction, a Digital Random Number +Generator (DRNG), which is functionally an high bandwidth entropy +source, cryptographic whitener, and integrity monitor all built into +hardware. This enables RDRAND to be used directly, bypassing the +kernel random number pool. + +For technical documentation, see: + +http://software.intel.com/en-us/articles/download-the-latest-bull-mountain-software-implementation-guide/ + +In this patch, this is *only* used for the nonblocking random number +pool. RDRAND is a nonblocking source, similar to our /dev/urandom, +and is therefore not a direct replacement for /dev/random. The +architectural hooks presented in the previous patch only feed the +kernel internal users, which only use the nonblocking pool, and so +this is not a problem. + +Since this instruction is available in userspace, there is no reason +to have a /dev/hw_rng device driver for the purpose of feeding rngd. +This is especially so since RDRAND is a nonblocking source, and needs +additional whitening and reduction (see the above technical +documentation for details) in order to be of "pure entropy source" +quality. + +The CONFIG_EXPERT compile-time option can be used to disable this use +of RDRAND. + +Signed-off-by: H. Peter Anvin +Originally-by: Fenghua Yu +Cc: Matt Mackall +Cc: Herbert Xu +Cc: "Theodore Ts'o" +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/Kconfig | 9 ++++ + arch/x86/include/asm/archrandom.h | 73 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1451,6 +1451,15 @@ config ARCH_USES_PG_UNCACHED + def_bool y + depends on X86_PAT + ++config ARCH_RANDOM ++ def_bool y ++ prompt "x86 architectural random number generator" if EXPERT ++ ---help--- ++ Enable the x86 architectural RDRAND instruction ++ (Intel Bull Mountain technology) to generate random numbers. ++ If supported, this is a high bandwidth, cryptographically ++ secure hardware random number generator. ++ + config EFI + bool "EFI runtime service support" + depends on ACPI +--- /dev/null ++++ b/arch/x86/include/asm/archrandom.h +@@ -0,0 +1,73 @@ ++/* ++ * This file is part of the Linux kernel. ++ * ++ * Copyright (c) 2011, Intel Corporation ++ * Authors: Fenghua Yu , ++ * H. Peter Anvin ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#ifndef ASM_X86_ARCHRANDOM_H ++#define ASM_X86_ARCHRANDOM_H ++ ++#include ++#include ++#include ++#include ++ ++#define RDRAND_RETRY_LOOPS 10 ++ ++#define RDRAND_INT ".byte 0x0f,0xc7,0xf0" ++#ifdef CONFIG_X86_64 ++# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0" ++#else ++# define RDRAND_LONG RDRAND_INT ++#endif ++ ++#ifdef CONFIG_ARCH_RANDOM ++ ++#define GET_RANDOM(name, type, rdrand, nop) \ ++static inline int name(type *v) \ ++{ \ ++ int ok; \ ++ alternative_io("movl $0, %0\n\t" \ ++ nop, \ ++ "\n1: " rdrand "\n\t" \ ++ "jc 2f\n\t" \ ++ "decl %0\n\t" \ ++ "jnz 1b\n\t" \ ++ "2:", \ ++ X86_FEATURE_RDRAND, \ ++ ASM_OUTPUT2("=r" (ok), "=a" (*v)), \ ++ "0" (RDRAND_RETRY_LOOPS)); \ ++ return ok; \ ++} ++ ++#ifdef CONFIG_X86_64 ++ ++GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP5); ++GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP4); ++ ++#else ++ ++GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP3); ++GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); ++ ++#endif /* CONFIG_X86_64 */ ++ ++#endif /* CONFIG_ARCH_RANDOM */ ++ ++#endif /* ASM_X86_ARCHRANDOM_H */ diff --git a/queue-3.0/x86-random-verify-rdrand-functionality-and-allow-it-to-be-disabled.patch b/queue-3.0/x86-random-verify-rdrand-functionality-and-allow-it-to-be-disabled.patch new file mode 100644 index 00000000000..1c2cf6ff079 --- /dev/null +++ b/queue-3.0/x86-random-verify-rdrand-functionality-and-allow-it-to-be-disabled.patch @@ -0,0 +1,158 @@ +From 49d859d78c5aeb998b6936fcb5f288f78d713489 Mon Sep 17 00:00:00 2001 +From: "H. Peter Anvin" +Date: Sun, 31 Jul 2011 14:02:19 -0700 +Subject: x86, random: Verify RDRAND functionality and allow it to be disabled + +From: "H. Peter Anvin" + +commit 49d859d78c5aeb998b6936fcb5f288f78d713489 upstream. + +If the CPU declares that RDRAND is available, go through a guranteed +reseed sequence, and make sure that it is actually working (producing +data.) If it does not, disable the CPU feature flag. + +Allow RDRAND to be disabled on the command line (as opposed to at +compile time) for a user who has special requirements with regards to +random numbers. + +Signed-off-by: H. Peter Anvin +Cc: Matt Mackall +Cc: Herbert Xu +Cc: "Theodore Ts'o" +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/kernel-parameters.txt | 5 ++ + arch/x86/include/asm/archrandom.h | 2 + arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/common.c | 2 + arch/x86/kernel/cpu/rdrand.c | 73 ++++++++++++++++++++++++++++++++++++ + 5 files changed, 83 insertions(+) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1764,6 +1764,11 @@ bytes respectively. Such letter suffixes + + noresidual [PPC] Don't use residual data on PReP machines. + ++ nordrand [X86] Disable the direct use of the RDRAND ++ instruction even if it is supported by the ++ processor. RDRAND is still available to user ++ space applications. ++ + noresume [SWSUSP] Disables resume and restores original swap + space. + +--- a/arch/x86/include/asm/archrandom.h ++++ b/arch/x86/include/asm/archrandom.h +@@ -70,4 +70,6 @@ GET_RANDOM(arch_get_random_int, unsigned + + #endif /* CONFIG_ARCH_RANDOM */ + ++extern void x86_init_rdrand(struct cpuinfo_x86 *c); ++ + #endif /* ASM_X86_ARCHRANDOM_H */ +--- a/arch/x86/kernel/cpu/Makefile ++++ b/arch/x86/kernel/cpu/Makefile +@@ -15,6 +15,7 @@ CFLAGS_common.o := $(nostackp) + obj-y := intel_cacheinfo.o scattered.o topology.o + obj-y += proc.o capflags.o powerflags.o common.o + obj-y += vmware.o hypervisor.o sched.o mshyperv.o ++obj-y += rdrand.o + + obj-$(CONFIG_X86_32) += bugs.o + obj-$(CONFIG_X86_64) += bugs_64.o +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -852,6 +853,7 @@ static void __cpuinit identify_cpu(struc + #endif + + init_hypervisor(c); ++ x86_init_rdrand(c); + + /* + * Clear/Set all flags overriden by options, need do it +--- /dev/null ++++ b/arch/x86/kernel/cpu/rdrand.c +@@ -0,0 +1,73 @@ ++/* ++ * This file is part of the Linux kernel. ++ * ++ * Copyright (c) 2011, Intel Corporation ++ * Authors: Fenghua Yu , ++ * H. Peter Anvin ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++static int __init x86_rdrand_setup(char *s) ++{ ++ setup_clear_cpu_cap(X86_FEATURE_RDRAND); ++ return 1; ++} ++__setup("nordrand", x86_rdrand_setup); ++ ++/* We can't use arch_get_random_long() here since alternatives haven't run */ ++static inline int rdrand_long(unsigned long *v) ++{ ++ int ok; ++ asm volatile("1: " RDRAND_LONG "\n\t" ++ "jc 2f\n\t" ++ "decl %0\n\t" ++ "jnz 1b\n\t" ++ "2:" ++ : "=r" (ok), "=a" (*v) ++ : "0" (RDRAND_RETRY_LOOPS)); ++ return ok; ++} ++ ++/* ++ * Force a reseed cycle; we are architecturally guaranteed a reseed ++ * after no more than 512 128-bit chunks of random data. This also ++ * acts as a test of the CPU capability. ++ */ ++#define RESEED_LOOP ((512*128)/sizeof(unsigned long)) ++ ++void __cpuinit x86_init_rdrand(struct cpuinfo_x86 *c) ++{ ++#ifdef CONFIG_ARCH_RANDOM ++ unsigned long tmp; ++ int i, count, ok; ++ ++ if (!cpu_has(c, X86_FEATURE_RDRAND)) ++ return; /* Nothing to do */ ++ ++ for (count = i = 0; i < RESEED_LOOP; i++) { ++ ok = rdrand_long(&tmp); ++ if (ok) ++ count++; ++ } ++ ++ if (count != RESEED_LOOP) ++ clear_cpu_cap(c, X86_FEATURE_RDRAND); ++#endif ++}