@@ -63,43 +63,75 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
63
63
static int __netlink_diag_dump (struct sk_buff * skb , struct netlink_callback * cb ,
64
64
int protocol , int s_num )
65
65
{
66
+ struct rhashtable_iter * hti = (void * )cb -> args [2 ];
66
67
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 );
69
68
struct net * net = sock_net (skb -> sk );
70
69
struct netlink_diag_req * req ;
71
70
struct netlink_sock * nlsk ;
72
71
struct sock * sk ;
73
- int ret = 0 , num = 0 , i ;
72
+ int num = 2 ;
73
+ int ret = 0 ;
74
74
75
75
req = nlmsg_data (cb -> nlh );
76
76
77
- for ( i = 0 ; i < htbl -> size ; i ++ ) {
78
- struct rhash_head * pos ;
77
+ if ( s_num > 1 )
78
+ goto mc_list ;
79
79
80
- rht_for_each_entry_rcu (nlsk , pos , htbl , i , node ) {
81
- sk = (struct sock * )nlsk ;
80
+ num -- ;
82
81
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 ;
87
104
continue ;
88
105
}
106
+ break ;
107
+ }
89
108
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 ;
98
110
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 ;
100
121
}
101
122
}
102
123
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 );
103
135
sk_for_each_bound (sk , & tbl -> mc_list ) {
104
136
if (sk_hashed (sk ))
105
137
continue ;
@@ -116,13 +148,14 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
116
148
NLM_F_MULTI ,
117
149
sock_i_ino (sk )) < 0 ) {
118
150
ret = 1 ;
119
- goto done ;
151
+ break ;
120
152
}
121
153
num ++ ;
122
154
}
155
+ read_unlock (& nl_table_lock );
156
+
123
157
done :
124
158
cb -> args [0 ] = num ;
125
- cb -> args [1 ] = protocol ;
126
159
127
160
return ret ;
128
161
}
@@ -131,34 +164,43 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
131
164
{
132
165
struct netlink_diag_req * req ;
133
166
int s_num = cb -> args [0 ];
167
+ int err = 0 ;
134
168
135
169
req = nlmsg_data (cb -> nlh );
136
170
137
- rcu_read_lock ();
138
- read_lock (& nl_table_lock );
139
-
140
171
if (req -> sdiag_protocol == NDIAG_PROTO_ALL ) {
141
172
int i ;
142
173
143
174
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 )
145
177
break ;
146
178
s_num = 0 ;
147
179
}
180
+ cb -> args [1 ] = i ;
148
181
} else {
149
182
if (req -> sdiag_protocol >= MAX_LINKS ) {
150
183
read_unlock (& nl_table_lock );
151
184
rcu_read_unlock ();
152
185
return - ENOENT ;
153
186
}
154
187
155
- __netlink_diag_dump (skb , cb , req -> sdiag_protocol , s_num );
188
+ err = __netlink_diag_dump (skb , cb , req -> sdiag_protocol , s_num );
156
189
}
157
190
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 );
160
200
161
- return skb -> len ;
201
+ kfree (hti );
202
+
203
+ return 0 ;
162
204
}
163
205
164
206
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)
172
214
if (h -> nlmsg_flags & NLM_F_DUMP ) {
173
215
struct netlink_dump_control c = {
174
216
.dump = netlink_diag_dump ,
217
+ .done = netlink_diag_dump_done ,
175
218
};
176
219
return netlink_dump_start (net -> diag_nlsk , skb , h , & c );
177
220
} else
0 commit comments