Skip to content

Commit

Permalink
SYSCTL: Print binary sysctl warnings (nearly) only once
Browse files Browse the repository at this point in the history
When printing legacy sysctls print the warning message
for each of them only once.  This way there is a guarantee
the syslog won't be flooded for any sane program.

The original attempt at this made the tables non const and stored
the flag inline.

Linus suggested using a separate hash table for this, this is based on a
code snippet from him.

The hash implies this is not exact and can sometimes not print a
new sysctl due to a hash collision, but in practice this should not
be a problem

I used a FNV32 hash over the binary string with a 32byte bitmap. This
gives relatively little collisions when all the predefined binary sysctls
are hashed:

size 256
bucket
length      number
0:          [25]
1:          [67]
2:          [88]
3:          [47]
4:          [22]
5:          [6]
6:          [1]

The worst case is a single collision of 6 hash values.

Signed-off-by: Andi Kleen <[email protected]>
  • Loading branch information
Andi Kleen committed Dec 23, 2009
1 parent f42ecb2 commit 4440095
Showing 1 changed file with 30 additions and 1 deletion.
31 changes: 30 additions & 1 deletion kernel/sysctl_binary.c
Original file line number Diff line number Diff line change
Expand Up @@ -1417,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)
{
Expand All @@ -1431,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);
}
Expand Down

0 comments on commit 4440095

Please sign in to comment.