@@ -63,43 +63,75 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
6363static 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+
123157done :
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
164206static 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