Skip to content

Commit 178883f

Browse files
Florian Westphalummakynes
authored andcommitted
ipvs: speed up reads from ip_vs_conn proc file
Reading is very slow because ->start() performs a linear re-scan of the entire hash table until it finds the successor to the last dumped element. The current implementation uses 'pos' as the 'number of elements to skip, then does linear iteration until it has skipped 'pos' entries. Store the last bucket and the number of elements to skip in that bucket instead, so we can resume from bucket b directly. before this patch, its possible to read ~35k entries in one second, but each read() gets slower as the number of entries to skip grows: time timeout 60 cat /proc/net/ip_vs_conn > /tmp/all; wc -l /tmp/all real 1m0.007s user 0m0.003s sys 0m59.956s 140386 /tmp/all Only ~100k more got read in remaining the remaining 59s, and did not get nowhere near the 1m entries that are stored at the time. after this patch, dump completes very quickly: time cat /proc/net/ip_vs_conn > /tmp/all; wc -l /tmp/all real 0m2.286s user 0m0.004s sys 0m2.281s 1000001 /tmp/all Signed-off-by: Florian Westphal <[email protected]> Acked-by: Julian Anastasov <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent da0a090 commit 178883f

File tree

1 file changed

+28
-22
lines changed

1 file changed

+28
-22
lines changed

net/netfilter/ipvs/ip_vs_conn.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,28 +1046,35 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
10461046
#ifdef CONFIG_PROC_FS
10471047
struct ip_vs_iter_state {
10481048
struct seq_net_private p;
1049-
struct hlist_head *l;
1049+
unsigned int bucket;
1050+
unsigned int skip_elems;
10501051
};
10511052

1052-
static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
1053+
static void *ip_vs_conn_array(struct ip_vs_iter_state *iter)
10531054
{
10541055
int idx;
10551056
struct ip_vs_conn *cp;
1056-
struct ip_vs_iter_state *iter = seq->private;
10571057

1058-
for (idx = 0; idx < ip_vs_conn_tab_size; idx++) {
1058+
for (idx = iter->bucket; idx < ip_vs_conn_tab_size; idx++) {
1059+
unsigned int skip = 0;
1060+
10591061
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
10601062
/* __ip_vs_conn_get() is not needed by
10611063
* ip_vs_conn_seq_show and ip_vs_conn_sync_seq_show
10621064
*/
1063-
if (pos-- == 0) {
1064-
iter->l = &ip_vs_conn_tab[idx];
1065+
if (skip >= iter->skip_elems) {
1066+
iter->bucket = idx;
10651067
return cp;
10661068
}
1069+
1070+
++skip;
10671071
}
1072+
1073+
iter->skip_elems = 0;
10681074
cond_resched_rcu();
10691075
}
10701076

1077+
iter->bucket = idx;
10711078
return NULL;
10721079
}
10731080

@@ -1076,38 +1083,37 @@ static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
10761083
{
10771084
struct ip_vs_iter_state *iter = seq->private;
10781085

1079-
iter->l = NULL;
10801086
rcu_read_lock();
1081-
return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;
1087+
if (*pos == 0) {
1088+
iter->skip_elems = 0;
1089+
iter->bucket = 0;
1090+
return SEQ_START_TOKEN;
1091+
}
1092+
1093+
return ip_vs_conn_array(iter);
10821094
}
10831095

10841096
static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
10851097
{
10861098
struct ip_vs_conn *cp = v;
10871099
struct ip_vs_iter_state *iter = seq->private;
10881100
struct hlist_node *e;
1089-
struct hlist_head *l = iter->l;
1090-
int idx;
10911101

10921102
++*pos;
10931103
if (v == SEQ_START_TOKEN)
1094-
return ip_vs_conn_array(seq, 0);
1104+
return ip_vs_conn_array(iter);
10951105

10961106
/* more on same hash chain? */
10971107
e = rcu_dereference(hlist_next_rcu(&cp->c_list));
1098-
if (e)
1108+
if (e) {
1109+
iter->skip_elems++;
10991110
return hlist_entry(e, struct ip_vs_conn, c_list);
1100-
1101-
idx = l - ip_vs_conn_tab;
1102-
while (++idx < ip_vs_conn_tab_size) {
1103-
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
1104-
iter->l = &ip_vs_conn_tab[idx];
1105-
return cp;
1106-
}
1107-
cond_resched_rcu();
11081111
}
1109-
iter->l = NULL;
1110-
return NULL;
1112+
1113+
iter->skip_elems = 0;
1114+
iter->bucket++;
1115+
1116+
return ip_vs_conn_array(iter);
11111117
}
11121118

11131119
static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v)

0 commit comments

Comments
 (0)