mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
![Sasha Levin](/assets/img/avatar_default.png)
I'm not sure why, but the hlist for each entry iterators were conceived list_for_each_entry(pos, head, member) The hlist ones were greedy and wanted an extra parameter: hlist_for_each_entry(tpos, pos, head, member) Why did they need an extra pos parameter? I'm not quite sure. Not only they don't really need it, it also prevents the iterator from looking exactly like the list iterator, which is unfortunate. Besides the semantic patch, there was some manual work required: - Fix up the actual hlist iterators in linux/list.h - Fix up the declaration of other iterators based on the hlist ones. - A very small amount of places were using the 'node' parameter, this was modified to use 'obj->member' instead. - Coccinelle didn't handle the hlist_for_each_entry_safe iterator properly, so those had to be fixed up manually. The semantic patch which is mostly the work of Peter Senna Tschudin is here: @@ iterator name hlist_for_each_entry, hlist_for_each_entry_continue, hlist_for_each_entry_from, hlist_for_each_entry_rcu, hlist_for_each_entry_rcu_bh, hlist_for_each_entry_continue_rcu_bh, for_each_busy_worker, ax25_uid_for_each, ax25_for_each, inet_bind_bucket_for_each, sctp_for_each_hentry, sk_for_each, sk_for_each_rcu, sk_for_each_from, sk_for_each_safe, sk_for_each_bound, hlist_for_each_entry_safe, hlist_for_each_entry_continue_rcu, nr_neigh_for_each, nr_neigh_for_each_safe, nr_node_for_each, nr_node_for_each_safe, for_each_gfn_indirect_valid_sp, for_each_gfn_sp, for_each_host; type T; expression a,c,d,e; identifier b; statement S; @@ -T b; <+... when != b ( hlist_for_each_entry(a, - b, c, d) S | hlist_for_each_entry_continue(a, - b, c) S | hlist_for_each_entry_from(a, - b, c) S | hlist_for_each_entry_rcu(a, - b, c, d) S | hlist_for_each_entry_rcu_bh(a, - b, c, d) S | hlist_for_each_entry_continue_rcu_bh(a, - b, c) S | for_each_busy_worker(a, c, - b, d) S | ax25_uid_for_each(a, - b, c) S | ax25_for_each(a, - b, c) S | inet_bind_bucket_for_each(a, - b, c) S | sctp_for_each_hentry(a, - b, c) S | sk_for_each(a, - b, c) S | sk_for_each_rcu(a, - b, c) S | sk_for_each_from -(a, b) +(a) S + sk_for_each_from(a) S | sk_for_each_safe(a, - b, c, d) S | sk_for_each_bound(a, - b, c) S | hlist_for_each_entry_safe(a, - b, c, d, e) S | hlist_for_each_entry_continue_rcu(a, - b, c) S | nr_neigh_for_each(a, - b, c) S | nr_neigh_for_each_safe(a, - b, c, d) S | nr_node_for_each(a, - b, c) S | nr_node_for_each_safe(a, - b, c, d) S | - for_each_gfn_sp(a, c, d, b) S + for_each_gfn_sp(a, c, d) S | - for_each_gfn_indirect_valid_sp(a, c, d, b) S + for_each_gfn_indirect_valid_sp(a, c, d) S | for_each_host(a, - b, c) S | for_each_host_safe(a, - b, c, d) S | for_each_mesh_entry(a, - b, c, d) S ) ...+> [akpm@linux-foundation.org: drop bogus change from net/ipv4/raw.c] [akpm@linux-foundation.org: drop bogus hunk from net/ipv6/raw.c] [akpm@linux-foundation.org: checkpatch fixes] [akpm@linux-foundation.org: fix warnings] [akpm@linux-foudnation.org: redo intrusive kvm changes] Tested-by: Peter Senna Tschudin <peter.senna@gmail.com> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Sasha Levin <sasha.levin@oracle.com> Cc: Wu Fengguang <fengguang.wu@intel.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: Gleb Natapov <gleb@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
194 lines
4.6 KiB
C
194 lines
4.6 KiB
C
/*
|
|
* (C) 2007 Patrick McHardy <kaber@trash.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/gen_stats.h>
|
|
#include <linux/jhash.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/random.h>
|
|
#include <linux/slab.h>
|
|
#include <net/gen_stats.h>
|
|
#include <net/netlink.h>
|
|
|
|
#include <linux/netfilter/x_tables.h>
|
|
#include <linux/netfilter/xt_RATEEST.h>
|
|
#include <net/netfilter/xt_rateest.h>
|
|
|
|
static DEFINE_MUTEX(xt_rateest_mutex);
|
|
|
|
#define RATEEST_HSIZE 16
|
|
static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
|
|
static unsigned int jhash_rnd __read_mostly;
|
|
static bool rnd_inited __read_mostly;
|
|
|
|
static unsigned int xt_rateest_hash(const char *name)
|
|
{
|
|
return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) &
|
|
(RATEEST_HSIZE - 1);
|
|
}
|
|
|
|
static void xt_rateest_hash_insert(struct xt_rateest *est)
|
|
{
|
|
unsigned int h;
|
|
|
|
h = xt_rateest_hash(est->name);
|
|
hlist_add_head(&est->list, &rateest_hash[h]);
|
|
}
|
|
|
|
struct xt_rateest *xt_rateest_lookup(const char *name)
|
|
{
|
|
struct xt_rateest *est;
|
|
unsigned int h;
|
|
|
|
h = xt_rateest_hash(name);
|
|
mutex_lock(&xt_rateest_mutex);
|
|
hlist_for_each_entry(est, &rateest_hash[h], list) {
|
|
if (strcmp(est->name, name) == 0) {
|
|
est->refcnt++;
|
|
mutex_unlock(&xt_rateest_mutex);
|
|
return est;
|
|
}
|
|
}
|
|
mutex_unlock(&xt_rateest_mutex);
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(xt_rateest_lookup);
|
|
|
|
void xt_rateest_put(struct xt_rateest *est)
|
|
{
|
|
mutex_lock(&xt_rateest_mutex);
|
|
if (--est->refcnt == 0) {
|
|
hlist_del(&est->list);
|
|
gen_kill_estimator(&est->bstats, &est->rstats);
|
|
/*
|
|
* gen_estimator est_timer() might access est->lock or bstats,
|
|
* wait a RCU grace period before freeing 'est'
|
|
*/
|
|
kfree_rcu(est, rcu);
|
|
}
|
|
mutex_unlock(&xt_rateest_mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(xt_rateest_put);
|
|
|
|
static unsigned int
|
|
xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
|
{
|
|
const struct xt_rateest_target_info *info = par->targinfo;
|
|
struct gnet_stats_basic_packed *stats = &info->est->bstats;
|
|
|
|
spin_lock_bh(&info->est->lock);
|
|
stats->bytes += skb->len;
|
|
stats->packets++;
|
|
spin_unlock_bh(&info->est->lock);
|
|
|
|
return XT_CONTINUE;
|
|
}
|
|
|
|
static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
|
|
{
|
|
struct xt_rateest_target_info *info = par->targinfo;
|
|
struct xt_rateest *est;
|
|
struct {
|
|
struct nlattr opt;
|
|
struct gnet_estimator est;
|
|
} cfg;
|
|
int ret;
|
|
|
|
if (unlikely(!rnd_inited)) {
|
|
get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
|
|
rnd_inited = true;
|
|
}
|
|
|
|
est = xt_rateest_lookup(info->name);
|
|
if (est) {
|
|
/*
|
|
* If estimator parameters are specified, they must match the
|
|
* existing estimator.
|
|
*/
|
|
if ((!info->interval && !info->ewma_log) ||
|
|
(info->interval != est->params.interval ||
|
|
info->ewma_log != est->params.ewma_log)) {
|
|
xt_rateest_put(est);
|
|
return -EINVAL;
|
|
}
|
|
info->est = est;
|
|
return 0;
|
|
}
|
|
|
|
ret = -ENOMEM;
|
|
est = kzalloc(sizeof(*est), GFP_KERNEL);
|
|
if (!est)
|
|
goto err1;
|
|
|
|
strlcpy(est->name, info->name, sizeof(est->name));
|
|
spin_lock_init(&est->lock);
|
|
est->refcnt = 1;
|
|
est->params.interval = info->interval;
|
|
est->params.ewma_log = info->ewma_log;
|
|
|
|
cfg.opt.nla_len = nla_attr_size(sizeof(cfg.est));
|
|
cfg.opt.nla_type = TCA_STATS_RATE_EST;
|
|
cfg.est.interval = info->interval;
|
|
cfg.est.ewma_log = info->ewma_log;
|
|
|
|
ret = gen_new_estimator(&est->bstats, &est->rstats,
|
|
&est->lock, &cfg.opt);
|
|
if (ret < 0)
|
|
goto err2;
|
|
|
|
info->est = est;
|
|
xt_rateest_hash_insert(est);
|
|
return 0;
|
|
|
|
err2:
|
|
kfree(est);
|
|
err1:
|
|
return ret;
|
|
}
|
|
|
|
static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
|
|
{
|
|
struct xt_rateest_target_info *info = par->targinfo;
|
|
|
|
xt_rateest_put(info->est);
|
|
}
|
|
|
|
static struct xt_target xt_rateest_tg_reg __read_mostly = {
|
|
.name = "RATEEST",
|
|
.revision = 0,
|
|
.family = NFPROTO_UNSPEC,
|
|
.target = xt_rateest_tg,
|
|
.checkentry = xt_rateest_tg_checkentry,
|
|
.destroy = xt_rateest_tg_destroy,
|
|
.targetsize = sizeof(struct xt_rateest_target_info),
|
|
.me = THIS_MODULE,
|
|
};
|
|
|
|
static int __init xt_rateest_tg_init(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rateest_hash); i++)
|
|
INIT_HLIST_HEAD(&rateest_hash[i]);
|
|
|
|
return xt_register_target(&xt_rateest_tg_reg);
|
|
}
|
|
|
|
static void __exit xt_rateest_tg_fini(void)
|
|
{
|
|
xt_unregister_target(&xt_rateest_tg_reg);
|
|
}
|
|
|
|
|
|
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("Xtables: packet rate estimator");
|
|
MODULE_ALIAS("ipt_RATEEST");
|
|
MODULE_ALIAS("ip6t_RATEEST");
|
|
module_init(xt_rateest_tg_init);
|
|
module_exit(xt_rateest_tg_fini);
|