summaryrefslogtreecommitdiffstats
path: root/kernel/sysctl_binary.c
diff options
context:
space:
mode:
authorJames Morris <jmorris@namei.org>2010-01-18 09:56:22 +1100
committerJames Morris <jmorris@namei.org>2010-01-18 09:56:22 +1100
commit2457552d1e6f3183cd93f81c49a8da5fe8bb0e42 (patch)
tree7ca46caa910012d75617700e4083b3657053cb31 /kernel/sysctl_binary.c
parent19439d05b88dafc4e55d9ffce84ccc27cf8b2bcc (diff)
parent6ccf80eb15ccaca4d3f1ab5162b9ded5eecd9971 (diff)
downloadkernel-crypto-2457552d1e6f3183cd93f81c49a8da5fe8bb0e42.tar.gz
kernel-crypto-2457552d1e6f3183cd93f81c49a8da5fe8bb0e42.tar.xz
kernel-crypto-2457552d1e6f3183cd93f81c49a8da5fe8bb0e42.zip
Merge branch 'master' into next
Diffstat (limited to 'kernel/sysctl_binary.c')
-rw-r--r--kernel/sysctl_binary.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index b75dbf40f57..8f5d16e0707 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1399,6 +1399,13 @@ static void deprecated_sysctl_warning(const int *name, int nlen)
{
int i;
+ /*
+ * CTL_KERN/KERN_VERSION is used by older glibc and cannot
+ * ever go away.
+ */
+ if (name[0] == CTL_KERN && name[1] == KERN_VERSION)
+ return;
+
if (printk_ratelimit()) {
printk(KERN_INFO
"warning: process `%s' used the deprecated sysctl "
@@ -1410,6 +1417,35 @@ static void deprecated_sysctl_warning(const int *name, int nlen)
return;
}
+#define WARN_ONCE_HASH_BITS 8
+#define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
+
+static DECLARE_BITMAP(warn_once_bitmap, WARN_ONCE_HASH_SIZE);
+
+#define FNV32_OFFSET 2166136261U
+#define FNV32_PRIME 0x01000193
+
+/*
+ * Print each legacy sysctl (approximately) only once.
+ * To avoid making the tables non-const use a external
+ * hash-table instead.
+ * Worst case hash collision: 6, but very rarely.
+ * NOTE! We don't use the SMP-safe bit tests. We simply
+ * don't care enough.
+ */
+static void warn_on_bintable(const int *name, int nlen)
+{
+ int i;
+ u32 hash = FNV32_OFFSET;
+
+ for (i = 0; i < nlen; i++)
+ hash = (hash ^ name[i]) * FNV32_PRIME;
+ hash %= WARN_ONCE_HASH_SIZE;
+ if (__test_and_set_bit(hash, warn_once_bitmap))
+ return;
+ deprecated_sysctl_warning(name, nlen);
+}
+
static ssize_t do_sysctl(int __user *args_name, int nlen,
void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
{
@@ -1424,7 +1460,7 @@ static ssize_t do_sysctl(int __user *args_name, int nlen,
if (get_user(name[i], args_name + i))
return -EFAULT;
- deprecated_sysctl_warning(name, nlen);
+ warn_on_bintable(name, nlen);
return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
}