Skip to content

Commit ad20207

Browse files
herbertxdavem330
authored andcommitted
netlink: Use rhashtable walk interface in diag dump
This patch converts the diag dumping code to use the rhashtable walk code instead of going through rhashtable by hand. The lock nl_table_lock is now only taken while we process the multicast list as it's not needed for the rhashtable walk. Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 39ec406 commit ad20207

File tree

1 file changed

+73
-30
lines changed

1 file changed

+73
-30
lines changed

net/netlink/diag.c

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,43 +63,75 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
6363
static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
6464
int protocol, int s_num)
6565
{
66+
struct rhashtable_iter *hti = (void *)cb->args[2];
6667
struct netlink_table *tbl = &nl_table[protocol];
67-
struct rhashtable *ht = &tbl->hash;
68-
const struct bucket_table *htbl = rht_dereference_rcu(ht->tbl, ht);
6968
struct net *net = sock_net(skb->sk);
7069
struct netlink_diag_req *req;
7170
struct netlink_sock *nlsk;
7271
struct sock *sk;
73-
int ret = 0, num = 0, i;
72+
int num = 2;
73+
int ret = 0;
7474

7575
req = nlmsg_data(cb->nlh);
7676

77-
for (i = 0; i < htbl->size; i++) {
78-
struct rhash_head *pos;
77+
if (s_num > 1)
78+
goto mc_list;
7979

80-
rht_for_each_entry_rcu(nlsk, pos, htbl, i, node) {
81-
sk = (struct sock *)nlsk;
80+
num--;
8281

83-
if (!net_eq(sock_net(sk), net))
84-
continue;
85-
if (num < s_num) {
86-
num++;
82+
if (!hti) {
83+
hti = kmalloc(sizeof(*hti), GFP_KERNEL);
84+
if (!hti)
85+
return -ENOMEM;
86+
87+
cb->args[2] = (long)hti;
88+
}
89+
90+
if (!s_num)
91+
rhashtable_walk_enter(&tbl->hash, hti);
92+
93+
ret = rhashtable_walk_start(hti);
94+
if (ret == -EAGAIN)
95+
ret = 0;
96+
if (ret)
97+
goto stop;
98+
99+
while ((nlsk = rhashtable_walk_next(hti))) {
100+
if (IS_ERR(nlsk)) {
101+
ret = PTR_ERR(nlsk);
102+
if (ret == -EAGAIN) {
103+
ret = 0;
87104
continue;
88105
}
106+
break;
107+
}
89108

90-
if (sk_diag_fill(sk, skb, req,
91-
NETLINK_CB(cb->skb).portid,
92-
cb->nlh->nlmsg_seq,
93-
NLM_F_MULTI,
94-
sock_i_ino(sk)) < 0) {
95-
ret = 1;
96-
goto done;
97-
}
109+
sk = (struct sock *)nlsk;
98110

99-
num++;
111+
if (!net_eq(sock_net(sk), net))
112+
continue;
113+
114+
if (sk_diag_fill(sk, skb, req,
115+
NETLINK_CB(cb->skb).portid,
116+
cb->nlh->nlmsg_seq,
117+
NLM_F_MULTI,
118+
sock_i_ino(sk)) < 0) {
119+
ret = 1;
120+
break;
100121
}
101122
}
102123

124+
stop:
125+
rhashtable_walk_stop(hti);
126+
if (ret)
127+
goto done;
128+
129+
rhashtable_walk_exit(hti);
130+
cb->args[2] = 0;
131+
num++;
132+
133+
mc_list:
134+
read_lock(&nl_table_lock);
103135
sk_for_each_bound(sk, &tbl->mc_list) {
104136
if (sk_hashed(sk))
105137
continue;
@@ -116,13 +148,14 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
116148
NLM_F_MULTI,
117149
sock_i_ino(sk)) < 0) {
118150
ret = 1;
119-
goto done;
151+
break;
120152
}
121153
num++;
122154
}
155+
read_unlock(&nl_table_lock);
156+
123157
done:
124158
cb->args[0] = num;
125-
cb->args[1] = protocol;
126159

127160
return ret;
128161
}
@@ -131,34 +164,43 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
131164
{
132165
struct netlink_diag_req *req;
133166
int s_num = cb->args[0];
167+
int err = 0;
134168

135169
req = nlmsg_data(cb->nlh);
136170

137-
rcu_read_lock();
138-
read_lock(&nl_table_lock);
139-
140171
if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
141172
int i;
142173

143174
for (i = cb->args[1]; i < MAX_LINKS; i++) {
144-
if (__netlink_diag_dump(skb, cb, i, s_num))
175+
err = __netlink_diag_dump(skb, cb, i, s_num);
176+
if (err)
145177
break;
146178
s_num = 0;
147179
}
180+
cb->args[1] = i;
148181
} else {
149182
if (req->sdiag_protocol >= MAX_LINKS) {
150183
read_unlock(&nl_table_lock);
151184
rcu_read_unlock();
152185
return -ENOENT;
153186
}
154187

155-
__netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
188+
err = __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
156189
}
157190

158-
read_unlock(&nl_table_lock);
159-
rcu_read_unlock();
191+
return err < 0 ? err : skb->len;
192+
}
193+
194+
static int netlink_diag_dump_done(struct netlink_callback *cb)
195+
{
196+
struct rhashtable_iter *hti = (void *)cb->args[2];
197+
198+
if (cb->args[0] == 1)
199+
rhashtable_walk_exit(hti);
160200

161-
return skb->len;
201+
kfree(hti);
202+
203+
return 0;
162204
}
163205

164206
static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
@@ -172,6 +214,7 @@ static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
172214
if (h->nlmsg_flags & NLM_F_DUMP) {
173215
struct netlink_dump_control c = {
174216
.dump = netlink_diag_dump,
217+
.done = netlink_diag_dump_done,
175218
};
176219
return netlink_dump_start(net->diag_nlsk, skb, h, &c);
177220
} else

0 commit comments

Comments
 (0)