Commit df428c06 authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji

[IPV{4,6}]: Fixing a bug that reading /proc/net/{udp,udp6} may drop some data.

parent d2231420
...@@ -1349,64 +1349,65 @@ struct proto udp_prot = { ...@@ -1349,64 +1349,65 @@ struct proto udp_prot = {
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static __inline__ struct sock *udp_get_bucket(struct seq_file *seq, loff_t *pos) static struct sock *udp_get_first(struct seq_file *seq)
{ {
int i;
struct sock *sk; struct sock *sk;
struct hlist_node *node;
loff_t l = *pos;
struct udp_iter_state *state = seq->private; struct udp_iter_state *state = seq->private;
for (; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
i = 0; struct hlist_node *node;
sk_for_each(sk, node, &udp_hash[state->bucket]) { sk_for_each(sk, node, &udp_hash[state->bucket]) {
if (sk->sk_family != state->family) { if (sk->sk_family == state->family)
++i; goto found;
continue;
}
if (l--) {
++i;
continue;
}
*pos = i;
goto out;
} }
} }
sk = NULL; sk = NULL;
out: found:
return sk; return sk;
} }
static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
{
struct udp_iter_state *state = seq->private;
do {
sk = sk_next(sk);
try_again:
;
} while (sk && sk->sk_family != state->family);
if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
sk = sk_head(&udp_hash[state->bucket]);
goto try_again;
}
return sk;
}
static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
{
struct sock *sk = udp_get_first(seq);
if (sk)
while(pos && (sk = udp_get_next(seq, sk)) != NULL)
--pos;
return pos ? NULL : sk;
}
static void *udp_seq_start(struct seq_file *seq, loff_t *pos) static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
{ {
read_lock(&udp_hash_lock); read_lock(&udp_hash_lock);
return *pos ? udp_get_bucket(seq, pos) : (void *)1; return *pos ? udp_get_idx(seq, *pos-1) : (void *)1;
} }
static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{ {
struct sock *sk; struct sock *sk;
struct hlist_node *node;
struct udp_iter_state *state;
if (v == (void *)1) {
sk = udp_get_bucket(seq, pos);
goto out;
}
state = seq->private;
sk = v;
sk_for_each_continue(sk, node)
if (sk->sk_family == state->family)
goto out;
if (++state->bucket >= UDP_HTABLE_SIZE) if (v == (void *)1)
goto out; sk = udp_get_idx(seq, 0);
else
sk = udp_get_next(seq, v);
*pos = 0;
sk = udp_get_bucket(seq, pos);
out:
++*pos; ++*pos;
return sk; return sk;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment