required to allow inlining of cmpfn. */
#define LIST_FIND(head, cmpfn, type, args...) \
({ \
- const struct list_head *__i = (head); \
+ const struct list_head *__i, *__j = NULL; \
\
ASSERT_READ_LOCK(head); \
- do { \
- __i = __i->next; \
- if (__i == (head)) { \
- __i = NULL; \
+ list_for_each(__i, (head)) \
+ if (cmpfn((const type)__i , ## args)) { \
+ __j = __i; \
break; \
} \
- } while (!cmpfn((const type)__i , ## args)); \
- (type)__i; \
+ (type)__j; \
})
-#define LIST_FIND_W(head, cmpfn, type, args...) \
-({ \
- const struct list_head *__i = (head); \
- \
- ASSERT_WRITE_LOCK(head); \
- do { \
- __i = __i->next; \
- if (__i == (head)) { \
- __i = NULL; \
- break; \
- } \
- } while (!cmpfn((type)__i , ## args)); \
- (type)__i; \
+#define LIST_FIND_W(head, cmpfn, type, args...) \
+({ \
+ const struct list_head *__i, *__j = NULL; \
+ \
+ ASSERT_WRITE_LOCK(head); \
+ list_for_each(__i, (head)) \
+ if (cmpfn((type)__i , ## args)) { \
+ __j = __i; \
+ break; \
+ } \
+ (type)__j; \
})
/* Just like LIST_FIND but we search backwards */
#define LIST_FIND_B(head, cmpfn, type, args...) \
({ \
- const struct list_head *__i = (head); \
+ const struct list_head *__i, *__j = NULL; \
\
ASSERT_READ_LOCK(head); \
- do { \
- __i = __i->prev; \
- if (__i == (head)) { \
- __i = NULL; \
+ list_for_each_prev(__i, (head)) \
+ if (cmpfn((const type)__i , ## args)) { \
+ __j = __i; \
break; \
} \
- } while (!cmpfn((const type)__i , ## args)); \
- (type)__i; \
+ (type)__j; \
})
static inline int
do { \
struct list_head *__i; \
ASSERT_WRITE_LOCK(head); \
- for (__i = (head)->next; \
- !cmpfn((new), (typeof (new))__i) && __i != (head); \
- __i = __i->next); \
+ list_for_each(__i, (head)) \
+ if ((new), (typeof (new))__i) \
+ break; \
list_add((struct list_head *)(new), __i->prev); \
} while(0)
/* Bring out ya dead! */
static struct ip_conntrack_tuple_hash *
get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
- void *data)
+ void *data, unsigned int *bucket)
{
struct ip_conntrack_tuple_hash *h = NULL;
- unsigned int i;
READ_LOCK(&ip_conntrack_lock);
- for (i = 0; !h && i < ip_conntrack_htable_size; i++) {
- h = LIST_FIND(&ip_conntrack_hash[i], do_kill,
+ for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
+ h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
struct ip_conntrack_tuple_hash *, kill, data);
}
if (h)
void *data)
{
struct ip_conntrack_tuple_hash *h;
+ unsigned int bucket = 0;
- /* This is order n^2, by the way. */
- while ((h = get_next_corpse(kill, data)) != NULL) {
+ while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
/* Time to push up daises... */
if (del_timer(&h->ctrack->timeout))
death_by_timeout((unsigned long)h->ctrack);
/* From ip_conntrack_core.c */
extern int ip_conntrack_max;
+extern unsigned int ip_conntrack_htable_size;
/* From ip_conntrack_proto_tcp.c */
extern unsigned long ip_ct_tcp_timeout_syn_sent;
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+ {
+ .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
+ .procname = "ip_conntrack_buckets",
+ .data = &ip_conntrack_htable_size,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0444,
+ .proc_handler = &proc_dointvec,
+ },
{
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
.procname = "ip_conntrack_tcp_timeout_syn_sent",