Merge branch 'master' of /repos/git/net-next-2.6
authorPatrick McHardy <kaber@trash.net>
Wed, 19 Jan 2011 22:51:37 +0000 (23:51 +0100)
committerPatrick McHardy <kaber@trash.net>
Wed, 19 Jan 2011 22:51:37 +0000 (23:51 +0100)
1  2 
include/linux/audit.h
include/linux/netfilter/x_tables.h
kernel/audit.c
net/ipv4/Kconfig
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv6/netfilter/ip6_tables.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/x_tables.c
net/sched/Kconfig

diff --combined include/linux/audit.h
  #define AUDIT_BPRM_FCAPS      1321    /* Information about fcaps increasing perms */
  #define AUDIT_CAPSET          1322    /* Record showing argument to sys_capset */
  #define AUDIT_MMAP            1323    /* Record showing descriptor and flags in mmap */
 +#define AUDIT_NETFILTER_PKT   1324    /* Packets traversing netfilter chains */
 +#define AUDIT_NETFILTER_CFG   1325    /* Netfilter chain modifications */
  
  #define AUDIT_AVC             1400    /* SE Linux avc denial or grant */
  #define AUDIT_SELINUX_ERR     1401    /* Internal SE Linux Errors */
@@@ -374,6 -372,7 +374,7 @@@ struct audit_buffer
  struct audit_context;
  struct inode;
  struct netlink_skb_parms;
+ struct path;
  struct linux_binprm;
  struct mq_attr;
  struct mqstat;
@@@ -472,7 -472,7 +472,7 @@@ extern void xt_free_table_info(struct x
   *  necessary for reading the counters.
   */
  struct xt_info_lock {
-       spinlock_t lock;
+       seqlock_t lock;
        unsigned char readers;
  };
  DECLARE_PER_CPU(struct xt_info_lock, xt_info_locks);
@@@ -497,7 -497,7 +497,7 @@@ static inline void xt_info_rdlock_bh(vo
        local_bh_disable();
        lock = &__get_cpu_var(xt_info_locks);
        if (likely(!lock->readers++))
-               spin_lock(&lock->lock);
+               write_seqlock(&lock->lock);
  }
  
  static inline void xt_info_rdunlock_bh(void)
        struct xt_info_lock *lock = &__get_cpu_var(xt_info_locks);
  
        if (likely(!--lock->readers))
-               spin_unlock(&lock->lock);
+               write_sequnlock(&lock->lock);
        local_bh_enable();
  }
  
   */
  static inline void xt_info_wrlock(unsigned int cpu)
  {
-       spin_lock(&per_cpu(xt_info_locks, cpu).lock);
+       write_seqlock(&per_cpu(xt_info_locks, cpu).lock);
  }
  
  static inline void xt_info_wrunlock(unsigned int cpu)
  {
-       spin_unlock(&per_cpu(xt_info_locks, cpu).lock);
+       write_sequnlock(&per_cpu(xt_info_locks, cpu).lock);
  }
  
  /*
@@@ -611,9 -611,8 +611,9 @@@ struct _compat_xt_align 
  extern void xt_compat_lock(u_int8_t af);
  extern void xt_compat_unlock(u_int8_t af);
  
 -extern int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta);
 +extern int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta);
  extern void xt_compat_flush_offsets(u_int8_t af);
 +extern void xt_compat_init_offsets(u_int8_t af, unsigned int number);
  extern int xt_compat_calc_jump(u_int8_t af, unsigned int offset);
  
  extern int xt_compat_match_offset(const struct xt_match *match);
diff --combined kernel/audit.c
@@@ -74,8 -74,6 +74,8 @@@ static int    audit_initialized
  int           audit_enabled;
  int           audit_ever_enabled;
  
 +EXPORT_SYMBOL_GPL(audit_enabled);
 +
  /* Default state when kernel boots without any parameters. */
  static int    audit_default;
  
@@@ -402,7 -400,7 +402,7 @@@ static void kauditd_send_skb(struct sk_
        if (err < 0) {
                BUG_ON(err != -ECONNREFUSED); /* Shouldn't happen */
                printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid);
-               audit_log_lost("auditd dissapeared\n");
+               audit_log_lost("auditd disappeared\n");
                audit_pid = 0;
                /* we might get lucky and get this in the next auditd */
                audit_hold_skb(skb);
diff --combined net/ipv4/Kconfig
@@@ -140,9 -140,6 +140,9 @@@ config IP_ROUTE_VERBOS
          handled by the klogd daemon which is responsible for kernel messages
          ("man klogd").
  
 +config IP_ROUTE_CLASSID
 +      bool
 +
  config IP_PNP
        bool "IP: kernel level autoconfiguration"
        help
@@@ -435,7 -432,9 +435,9 @@@ config INET_DIA
        ---help---
          Support for INET (TCP, DCCP, etc) socket monitoring interface used by
          native Linux tools such as ss. ss is included in iproute2, currently
-         downloadable at <http://linux-net.osdl.org/index.php/Iproute2>.
+         downloadable at:
+         
+           http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
  
          If unsure, say Y.
  
@@@ -658,3 -657,4 +660,3 @@@ config TCP_MD5SI
          on the Internet.
  
          If unsure, say N.
 -
@@@ -710,42 -710,25 +710,25 @@@ static void get_counters(const struct x
        struct arpt_entry *iter;
        unsigned int cpu;
        unsigned int i;
-       unsigned int curcpu = get_cpu();
-       /* Instead of clearing (by a previous call to memset())
-        * the counters and using adds, we set the counters
-        * with data used by 'current' CPU
-        *
-        * Bottom half has to be disabled to prevent deadlock
-        * if new softirq were to run and call ipt_do_table
-        */
-       local_bh_disable();
-       i = 0;
-       xt_entry_foreach(iter, t->entries[curcpu], t->size) {
-               SET_COUNTER(counters[i], iter->counters.bcnt,
-                           iter->counters.pcnt);
-               ++i;
-       }
-       local_bh_enable();
-       /* Processing counters from other cpus, we can let bottom half enabled,
-        * (preemption is disabled)
-        */
  
        for_each_possible_cpu(cpu) {
-               if (cpu == curcpu)
-                       continue;
+               seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
                i = 0;
-               local_bh_disable();
-               xt_info_wrlock(cpu);
                xt_entry_foreach(iter, t->entries[cpu], t->size) {
-                       ADD_COUNTER(counters[i], iter->counters.bcnt,
-                                   iter->counters.pcnt);
+                       u64 bcnt, pcnt;
+                       unsigned int start;
+                       do {
+                               start = read_seqbegin(lock);
+                               bcnt = iter->counters.bcnt;
+                               pcnt = iter->counters.pcnt;
+                       } while (read_seqretry(lock, start));
+                       ADD_COUNTER(counters[i], bcnt, pcnt);
                        ++i;
                }
-               xt_info_wrunlock(cpu);
-               local_bh_enable();
        }
-       put_cpu();
  }
  
  static struct xt_counters *alloc_counters(const struct xt_table *table)
         * about).
         */
        countersize = sizeof(struct xt_counters) * private->number;
-       counters = vmalloc(countersize);
+       counters = vzalloc(countersize);
  
        if (counters == NULL)
                return ERR_PTR(-ENOMEM);
@@@ -883,7 -866,6 +866,7 @@@ static int compat_table_info(const stru
        memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
        newinfo->initial_entries = 0;
        loc_cpu_entry = info->entries[raw_smp_processor_id()];
 +      xt_compat_init_offsets(NFPROTO_ARP, info->number);
        xt_entry_foreach(iter, loc_cpu_entry, info->size) {
                ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
                if (ret != 0)
@@@ -1008,7 -990,7 +991,7 @@@ static int __do_replace(struct net *net
        struct arpt_entry *iter;
  
        ret = 0;
-       counters = vmalloc(num_counters * sizeof(struct xt_counters));
+       counters = vzalloc(num_counters * sizeof(struct xt_counters));
        if (!counters) {
                ret = -ENOMEM;
                goto out;
@@@ -1351,7 -1333,6 +1334,7 @@@ static int translate_compat_table(cons
        duprintf("translate_compat_table: size %u\n", info->size);
        j = 0;
        xt_compat_lock(NFPROTO_ARP);
 +      xt_compat_init_offsets(NFPROTO_ARP, number);
        /* Walk through entries, checking offsets. */
        xt_entry_foreach(iter0, entry0, total_size) {
                ret = check_compat_entry_size_and_hooks(iter0, info, &size,
@@@ -884,42 -884,25 +884,25 @@@ get_counters(const struct xt_table_inf
        struct ipt_entry *iter;
        unsigned int cpu;
        unsigned int i;
-       unsigned int curcpu = get_cpu();
-       /* Instead of clearing (by a previous call to memset())
-        * the counters and using adds, we set the counters
-        * with data used by 'current' CPU.
-        *
-        * Bottom half has to be disabled to prevent deadlock
-        * if new softirq were to run and call ipt_do_table
-        */
-       local_bh_disable();
-       i = 0;
-       xt_entry_foreach(iter, t->entries[curcpu], t->size) {
-               SET_COUNTER(counters[i], iter->counters.bcnt,
-                           iter->counters.pcnt);
-               ++i;
-       }
-       local_bh_enable();
-       /* Processing counters from other cpus, we can let bottom half enabled,
-        * (preemption is disabled)
-        */
  
        for_each_possible_cpu(cpu) {
-               if (cpu == curcpu)
-                       continue;
+               seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
                i = 0;
-               local_bh_disable();
-               xt_info_wrlock(cpu);
                xt_entry_foreach(iter, t->entries[cpu], t->size) {
-                       ADD_COUNTER(counters[i], iter->counters.bcnt,
-                                   iter->counters.pcnt);
+                       u64 bcnt, pcnt;
+                       unsigned int start;
+                       do {
+                               start = read_seqbegin(lock);
+                               bcnt = iter->counters.bcnt;
+                               pcnt = iter->counters.pcnt;
+                       } while (read_seqretry(lock, start));
+                       ADD_COUNTER(counters[i], bcnt, pcnt);
                        ++i; /* macro does multi eval of i */
                }
-               xt_info_wrunlock(cpu);
-               local_bh_enable();
        }
-       put_cpu();
  }
  
  static struct xt_counters *alloc_counters(const struct xt_table *table)
           (other than comefrom, which userspace doesn't care
           about). */
        countersize = sizeof(struct xt_counters) * private->number;
-       counters = vmalloc(countersize);
+       counters = vzalloc(countersize);
  
        if (counters == NULL)
                return ERR_PTR(-ENOMEM);
@@@ -1080,7 -1063,6 +1063,7 @@@ static int compat_table_info(const stru
        memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
        newinfo->initial_entries = 0;
        loc_cpu_entry = info->entries[raw_smp_processor_id()];
 +      xt_compat_init_offsets(AF_INET, info->number);
        xt_entry_foreach(iter, loc_cpu_entry, info->size) {
                ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
                if (ret != 0)
@@@ -1204,7 -1186,7 +1187,7 @@@ __do_replace(struct net *net, const cha
        struct ipt_entry *iter;
  
        ret = 0;
-       counters = vmalloc(num_counters * sizeof(struct xt_counters));
+       counters = vzalloc(num_counters * sizeof(struct xt_counters));
        if (!counters) {
                ret = -ENOMEM;
                goto out;
@@@ -1682,7 -1664,6 +1665,7 @@@ translate_compat_table(struct net *net
        duprintf("translate_compat_table: size %u\n", info->size);
        j = 0;
        xt_compat_lock(AF_INET);
 +      xt_compat_init_offsets(AF_INET, number);
        /* Walk through entries, checking offsets. */
        xt_entry_foreach(iter0, entry0, total_size) {
                ret = check_compat_entry_size_and_hooks(iter0, info, &size,
@@@ -897,42 -897,25 +897,25 @@@ get_counters(const struct xt_table_inf
        struct ip6t_entry *iter;
        unsigned int cpu;
        unsigned int i;
-       unsigned int curcpu = get_cpu();
-       /* Instead of clearing (by a previous call to memset())
-        * the counters and using adds, we set the counters
-        * with data used by 'current' CPU
-        *
-        * Bottom half has to be disabled to prevent deadlock
-        * if new softirq were to run and call ipt_do_table
-        */
-       local_bh_disable();
-       i = 0;
-       xt_entry_foreach(iter, t->entries[curcpu], t->size) {
-               SET_COUNTER(counters[i], iter->counters.bcnt,
-                           iter->counters.pcnt);
-               ++i;
-       }
-       local_bh_enable();
-       /* Processing counters from other cpus, we can let bottom half enabled,
-        * (preemption is disabled)
-        */
  
        for_each_possible_cpu(cpu) {
-               if (cpu == curcpu)
-                       continue;
+               seqlock_t *lock = &per_cpu(xt_info_locks, cpu).lock;
                i = 0;
-               local_bh_disable();
-               xt_info_wrlock(cpu);
                xt_entry_foreach(iter, t->entries[cpu], t->size) {
-                       ADD_COUNTER(counters[i], iter->counters.bcnt,
-                                   iter->counters.pcnt);
+                       u64 bcnt, pcnt;
+                       unsigned int start;
+                       do {
+                               start = read_seqbegin(lock);
+                               bcnt = iter->counters.bcnt;
+                               pcnt = iter->counters.pcnt;
+                       } while (read_seqretry(lock, start));
+                       ADD_COUNTER(counters[i], bcnt, pcnt);
                        ++i;
                }
-               xt_info_wrunlock(cpu);
-               local_bh_enable();
        }
-       put_cpu();
  }
  
  static struct xt_counters *alloc_counters(const struct xt_table *table)
           (other than comefrom, which userspace doesn't care
           about). */
        countersize = sizeof(struct xt_counters) * private->number;
-       counters = vmalloc(countersize);
+       counters = vzalloc(countersize);
  
        if (counters == NULL)
                return ERR_PTR(-ENOMEM);
@@@ -1093,7 -1076,6 +1076,7 @@@ static int compat_table_info(const stru
        memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
        newinfo->initial_entries = 0;
        loc_cpu_entry = info->entries[raw_smp_processor_id()];
 +      xt_compat_init_offsets(AF_INET6, info->number);
        xt_entry_foreach(iter, loc_cpu_entry, info->size) {
                ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
                if (ret != 0)
@@@ -1217,7 -1199,7 +1200,7 @@@ __do_replace(struct net *net, const cha
        struct ip6t_entry *iter;
  
        ret = 0;
-       counters = vmalloc(num_counters * sizeof(struct xt_counters));
+       counters = vzalloc(num_counters * sizeof(struct xt_counters));
        if (!counters) {
                ret = -ENOMEM;
                goto out;
@@@ -1697,7 -1679,6 +1680,7 @@@ translate_compat_table(struct net *net
        duprintf("translate_compat_table: size %u\n", info->size);
        j = 0;
        xt_compat_lock(AF_INET6);
 +      xt_compat_init_offsets(AF_INET6, number);
        /* Walk through entries, checking offsets. */
        xt_entry_foreach(iter0, entry0, total_size) {
                ret = check_compat_entry_size_and_hooks(iter0, info, &size,
@@@ -42,7 -42,6 +42,7 @@@
  #include <net/netfilter/nf_conntrack_tuple.h>
  #include <net/netfilter/nf_conntrack_acct.h>
  #include <net/netfilter/nf_conntrack_zones.h>
 +#include <net/netfilter/nf_conntrack_timestamp.h>
  #ifdef CONFIG_NF_NAT_NEEDED
  #include <net/netfilter/nf_nat_core.h>
  #include <net/netfilter/nf_nat_protocol.h>
@@@ -231,33 -230,6 +231,33 @@@ nla_put_failure
        return -1;
  }
  
 +static int
 +ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
 +{
 +      struct nlattr *nest_count;
 +      const struct nf_conn_tstamp *tstamp;
 +
 +      tstamp = nf_conn_tstamp_find(ct);
 +      if (!tstamp)
 +              return 0;
 +
 +      nest_count = nla_nest_start(skb, CTA_TIMESTAMP | NLA_F_NESTED);
 +      if (!nest_count)
 +              goto nla_put_failure;
 +
 +      NLA_PUT_BE64(skb, CTA_TIMESTAMP_START, cpu_to_be64(tstamp->start));
 +      if (tstamp->stop != 0) {
 +              NLA_PUT_BE64(skb, CTA_TIMESTAMP_STOP,
 +                           cpu_to_be64(tstamp->stop));
 +      }
 +      nla_nest_end(skb, nest_count);
 +
 +      return 0;
 +
 +nla_put_failure:
 +      return -1;
 +}
 +
  #ifdef CONFIG_NF_CONNTRACK_MARK
  static inline int
  ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
@@@ -432,7 -404,6 +432,7 @@@ ctnetlink_fill_info(struct sk_buff *skb
            ctnetlink_dump_timeout(skb, ct) < 0 ||
            ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
            ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
 +          ctnetlink_dump_timestamp(skb, ct) < 0 ||
            ctnetlink_dump_protoinfo(skb, ct) < 0 ||
            ctnetlink_dump_helpinfo(skb, ct) < 0 ||
            ctnetlink_dump_mark(skb, ct) < 0 ||
@@@ -499,18 -470,6 +499,18 @@@ ctnetlink_secctx_size(const struct nf_c
  #endif
  }
  
 +static inline size_t
 +ctnetlink_timestamp_size(const struct nf_conn *ct)
 +{
 +#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
 +      if (!nf_ct_ext_exist(ct, NF_CT_EXT_TSTAMP))
 +              return 0;
 +      return nla_total_size(0) + 2 * nla_total_size(sizeof(uint64_t));
 +#else
 +      return 0;
 +#endif
 +}
 +
  static inline size_t
  ctnetlink_nlmsg_size(const struct nf_conn *ct)
  {
               + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
               + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
               + ctnetlink_counters_size(ct)
 +             + ctnetlink_timestamp_size(ct)
               + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
               + nla_total_size(0) /* CTA_PROTOINFO */
               + nla_total_size(0) /* CTA_HELP */
@@@ -613,8 -571,7 +613,8 @@@ ctnetlink_conntrack_event(unsigned int 
  
        if (events & (1 << IPCT_DESTROY)) {
                if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
 -                  ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
 +                  ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
 +                  ctnetlink_dump_timestamp(skb, ct) < 0)
                        goto nla_put_failure;
        } else {
                if (ctnetlink_dump_timeout(skb, ct) < 0)
@@@ -688,25 -645,23 +688,23 @@@ ctnetlink_dump_table(struct sk_buff *sk
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
  
-       rcu_read_lock();
+       spin_lock_bh(&nf_conntrack_lock);
        last = (struct nf_conn *)cb->args[1];
        for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
  restart:
-               hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[cb->args[0]],
+               hlist_nulls_for_each_entry(h, n, &net->ct.hash[cb->args[0]],
                                         hnnode) {
                        if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
                                continue;
                        ct = nf_ct_tuplehash_to_ctrack(h);
-                       if (!atomic_inc_not_zero(&ct->ct_general.use))
-                               continue;
                        /* Dump entries of a given L3 protocol number.
                         * If it is not specified, ie. l3proto == 0,
                         * then dump everything. */
                        if (l3proto && nf_ct_l3num(ct) != l3proto)
-                               goto releasect;
+                               continue;
                        if (cb->args[1]) {
                                if (ct != last)
-                                       goto releasect;
+                                       continue;
                                cb->args[1] = 0;
                        }
                        if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
                                if (acct)
                                        memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]));
                        }
- releasect:
-               nf_ct_put(ct);
                }
                if (cb->args[1]) {
                        cb->args[1] = 0;
                }
        }
  out:
-       rcu_read_unlock();
+       spin_unlock_bh(&nf_conntrack_lock);
        if (last)
                nf_ct_put(last);
  
@@@ -971,7 -924,7 +967,7 @@@ ctnetlink_get_conntrack(struct sock *ct
        u16 zone;
        int err;
  
-       if (nlh->nlmsg_flags & NLM_F_DUMP)
+       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
                return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
                                          ctnetlink_done);
  
  free:
        kfree_skb(skb2);
  out:
-       return err;
+       /* this avoids a loop in nfnetlink. */
+       return err == -EAGAIN ? -ENOBUFS : err;
  }
  
  #ifdef CONFIG_NF_NAT_NEEDED
@@@ -1403,7 -1357,6 +1400,7 @@@ ctnetlink_create_conntrack(struct net *
        }
  
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
 +      nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
        nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
        /* we must add conntrack extensions before confirmation. */
        ct->status |= IPS_CONFIRMED;
        }
  #endif
  
 +      memset(&ct->proto, 0, sizeof(ct->proto));
        if (cda[CTA_PROTOINFO]) {
                err = ctnetlink_change_protoinfo(ct, cda);
                if (err < 0)
@@@ -1835,7 -1787,7 +1832,7 @@@ ctnetlink_get_expect(struct sock *ctnl
        u16 zone;
        int err;
  
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
                return netlink_dump_start(ctnl, skb, nlh,
                                          ctnetlink_exp_dump_table,
                                          ctnetlink_exp_done);
diff --combined net/netfilter/x_tables.c
@@@ -23,7 -23,6 +23,7 @@@
  #include <linux/mutex.h>
  #include <linux/mm.h>
  #include <linux/slab.h>
 +#include <linux/audit.h>
  #include <net/net_namespace.h>
  
  #include <linux/netfilter/x_tables.h>
@@@ -39,8 -38,9 +39,8 @@@ MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tab
  #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
  
  struct compat_delta {
 -      struct compat_delta *next;
 -      unsigned int offset;
 -      int delta;
 +      unsigned int offset; /* offset in kernel */
 +      int delta; /* delta in 32bit user land */
  };
  
  struct xt_af {
@@@ -49,9 -49,7 +49,9 @@@
        struct list_head target;
  #ifdef CONFIG_COMPAT
        struct mutex compat_mutex;
 -      struct compat_delta *compat_offsets;
 +      struct compat_delta *compat_tab;
 +      unsigned int number; /* number of slots in compat_tab[] */
 +      unsigned int cur; /* number of used slots in compat_tab[] */
  #endif
  };
  
@@@ -416,67 -414,54 +416,67 @@@ int xt_check_match(struct xt_mtchk_para
  EXPORT_SYMBOL_GPL(xt_check_match);
  
  #ifdef CONFIG_COMPAT
 -int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta)
 +int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta)
  {
 -      struct compat_delta *tmp;
 +      struct xt_af *xp = &xt[af];
  
 -      tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
 -      if (!tmp)
 -              return -ENOMEM;
 +      if (!xp->compat_tab) {
 +              if (!xp->number)
 +                      return -EINVAL;
 +              xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number);
 +              if (!xp->compat_tab)
 +                      return -ENOMEM;
 +              xp->cur = 0;
 +      }
  
 -      tmp->offset = offset;
 -      tmp->delta = delta;
 +      if (xp->cur >= xp->number)
 +              return -EINVAL;
  
 -      if (xt[af].compat_offsets) {
 -              tmp->next = xt[af].compat_offsets->next;
 -              xt[af].compat_offsets->next = tmp;
 -      } else {
 -              xt[af].compat_offsets = tmp;
 -              tmp->next = NULL;
 -      }
 +      if (xp->cur)
 +              delta += xp->compat_tab[xp->cur - 1].delta;
 +      xp->compat_tab[xp->cur].offset = offset;
 +      xp->compat_tab[xp->cur].delta = delta;
 +      xp->cur++;
        return 0;
  }
  EXPORT_SYMBOL_GPL(xt_compat_add_offset);
  
  void xt_compat_flush_offsets(u_int8_t af)
  {
 -      struct compat_delta *tmp, *next;
 -
 -      if (xt[af].compat_offsets) {
 -              for (tmp = xt[af].compat_offsets; tmp; tmp = next) {
 -                      next = tmp->next;
 -                      kfree(tmp);
 -              }
 -              xt[af].compat_offsets = NULL;
 +      if (xt[af].compat_tab) {
 +              vfree(xt[af].compat_tab);
 +              xt[af].compat_tab = NULL;
 +              xt[af].number = 0;
        }
  }
  EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
  
  int xt_compat_calc_jump(u_int8_t af, unsigned int offset)
  {
 -      struct compat_delta *tmp;
 -      int delta;
 -
 -      for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
 -              if (tmp->offset < offset)
 -                      delta += tmp->delta;
 -      return delta;
 +      struct compat_delta *tmp = xt[af].compat_tab;
 +      int mid, left = 0, right = xt[af].cur - 1;
 +
 +      while (left <= right) {
 +              mid = (left + right) >> 1;
 +              if (offset > tmp[mid].offset)
 +                      left = mid + 1;
 +              else if (offset < tmp[mid].offset)
 +                      right = mid - 1;
 +              else
 +                      return mid ? tmp[mid - 1].delta : 0;
 +      }
 +      WARN_ON_ONCE(1);
 +      return 0;
  }
  EXPORT_SYMBOL_GPL(xt_compat_calc_jump);
  
 +void xt_compat_init_offsets(u_int8_t af, unsigned int number)
 +{
 +      xt[af].number = number;
 +      xt[af].cur = 0;
 +}
 +EXPORT_SYMBOL(xt_compat_init_offsets);
 +
  int xt_compat_match_offset(const struct xt_match *match)
  {
        u_int16_t csize = match->compatsize ? : match->matchsize;
@@@ -835,21 -820,6 +835,21 @@@ xt_replace_table(struct xt_table *table
         */
        local_bh_enable();
  
 +#ifdef CONFIG_AUDIT
 +      if (audit_enabled) {
 +              struct audit_buffer *ab;
 +
 +              ab = audit_log_start(current->audit_context, GFP_KERNEL,
 +                                   AUDIT_NETFILTER_CFG);
 +              if (ab) {
 +                      audit_log_format(ab, "table=%s family=%u entries=%u",
 +                                       table->name, table->af,
 +                                       private->number);
 +                      audit_log_end(ab);
 +              }
 +      }
 +#endif
 +
        return private;
  }
  EXPORT_SYMBOL_GPL(xt_replace_table);
@@@ -1355,7 -1325,8 +1355,8 @@@ static int __init xt_init(void
  
        for_each_possible_cpu(i) {
                struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
-               spin_lock_init(&lock->lock);
+               seqlock_init(&lock->lock);
                lock->readers = 0;
        }
  
                mutex_init(&xt[i].mutex);
  #ifdef CONFIG_COMPAT
                mutex_init(&xt[i].compat_mutex);
 -              xt[i].compat_offsets = NULL;
 +              xt[i].compat_tab = NULL;
  #endif
                INIT_LIST_HEAD(&xt[i].target);
                INIT_LIST_HEAD(&xt[i].match);
diff --combined net/sched/Kconfig
@@@ -24,7 -24,7 +24,7 @@@ menuconfig NET_SCHE
          To administer these schedulers, you'll need the user-level utilities
          from the package iproute2+tc at <ftp://ftp.tux.org/pub/net/ip-routing/>.
          That package also contains some documentation; for more, check out
-         <http://linux-net.osdl.org/index.php/Iproute2>.
+         <http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2>.
  
          This Quality of Service (QoS) support will enable you to use
          Differentiated Services (diffserv) and Resource Reservation Protocol
@@@ -243,7 -243,7 +243,7 @@@ config NET_CLS_TCINDE
  
  config NET_CLS_ROUTE4
        tristate "Routing decision (ROUTE)"
 -      select NET_CLS_ROUTE
 +      select IP_ROUTE_CLASSID
        select NET_CLS
        ---help---
          If you say Y here, you will be able to classify packets
          To compile this code as a module, choose M here: the
          module will be called cls_route.
  
 -config NET_CLS_ROUTE
 -      bool
 -
  config NET_CLS_FW
        tristate "Netfilter mark (FW)"
        select NET_CLS