Commit 4440095c8268c1a5e11577097d2be429cec036ca

Authored by Andi Kleen
1 parent f42ecb2808

SYSCTL: Print binary sysctl warnings (nearly) only once

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 <ak@linux.intel.com>

Showing 1 changed file with 30 additions and 1 deletions Side-by-side Diff

kernel/sysctl_binary.c
... ... @@ -1417,6 +1417,35 @@
1417 1417 return;
1418 1418 }
1419 1419  
  1420 +#define WARN_ONCE_HASH_BITS 8
  1421 +#define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
  1422 +
  1423 +static DECLARE_BITMAP(warn_once_bitmap, WARN_ONCE_HASH_SIZE);
  1424 +
  1425 +#define FNV32_OFFSET 2166136261U
  1426 +#define FNV32_PRIME 0x01000193
  1427 +
  1428 +/*
  1429 + * Print each legacy sysctl (approximately) only once.
  1430 + * To avoid making the tables non-const use a external
  1431 + * hash-table instead.
  1432 + * Worst case hash collision: 6, but very rarely.
  1433 + * NOTE! We don't use the SMP-safe bit tests. We simply
  1434 + * don't care enough.
  1435 + */
  1436 +static void warn_on_bintable(const int *name, int nlen)
  1437 +{
  1438 + int i;
  1439 + u32 hash = FNV32_OFFSET;
  1440 +
  1441 + for (i = 0; i < nlen; i++)
  1442 + hash = (hash ^ name[i]) * FNV32_PRIME;
  1443 + hash %= WARN_ONCE_HASH_SIZE;
  1444 + if (__test_and_set_bit(hash, warn_once_bitmap))
  1445 + return;
  1446 + deprecated_sysctl_warning(name, nlen);
  1447 +}
  1448 +
1420 1449 static ssize_t do_sysctl(int __user *args_name, int nlen,
1421 1450 void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
1422 1451 {
... ... @@ -1431,7 +1460,7 @@
1431 1460 if (get_user(name[i], args_name + i))
1432 1461 return -EFAULT;
1433 1462  
1434   - deprecated_sysctl_warning(name, nlen);
  1463 + warn_on_bintable(name, nlen);
1435 1464  
1436 1465 return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
1437 1466 }