@@ -990,20 +990,21 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
990990 struct fib_dump_filter filter = {
991991 .dump_routes = true,
992992 .dump_exceptions = true,
993- .rtnl_held = true ,
993+ .rtnl_held = false ,
994994 };
995995 const struct nlmsghdr * nlh = cb -> nlh ;
996996 struct net * net = sock_net (skb -> sk );
997997 unsigned int h , s_h ;
998998 unsigned int e = 0 , s_e ;
999999 struct fib_table * tb ;
10001000 struct hlist_head * head ;
1001- int dumped = 0 , err ;
1001+ int dumped = 0 , err = 0 ;
10021002
1003+ rcu_read_lock ();
10031004 if (cb -> strict_check ) {
10041005 err = ip_valid_fib_dump_req (net , nlh , & filter , cb );
10051006 if (err < 0 )
1006- return err ;
1007+ goto unlock ;
10071008 } else if (nlmsg_len (nlh ) >= sizeof (struct rtmsg )) {
10081009 struct rtmsg * rtm = nlmsg_data (nlh );
10091010
@@ -1012,29 +1013,28 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
10121013
10131014 /* ipv4 does not use prefix flag */
10141015 if (filter .flags & RTM_F_PREFIX )
1015- return skb -> len ;
1016+ goto unlock ;
10161017
10171018 if (filter .table_id ) {
10181019 tb = fib_get_table (net , filter .table_id );
10191020 if (!tb ) {
10201021 if (rtnl_msg_family (cb -> nlh ) != PF_INET )
1021- return skb -> len ;
1022+ goto unlock ;
10221023
10231024 NL_SET_ERR_MSG (cb -> extack , "ipv4: FIB table does not exist" );
1024- return - ENOENT ;
1025+ err = - ENOENT ;
1026+ goto unlock ;
10251027 }
1026-
1027- rcu_read_lock ();
10281028 err = fib_table_dump (tb , skb , cb , & filter );
1029- rcu_read_unlock ();
1030- return skb -> len ? : err ;
1029+ if (err < 0 && skb -> len )
1030+ err = skb -> len ;
1031+ goto unlock ;
10311032 }
10321033
10331034 s_h = cb -> args [0 ];
10341035 s_e = cb -> args [1 ];
10351036
1036- rcu_read_lock ();
1037-
1037+ err = 0 ;
10381038 for (h = s_h ; h < FIB_TABLE_HASHSZ ; h ++ , s_e = 0 ) {
10391039 e = 0 ;
10401040 head = & net -> ipv4 .fib_table_hash [h ];
@@ -1047,23 +1047,21 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
10471047 err = fib_table_dump (tb , skb , cb , & filter );
10481048 if (err < 0 ) {
10491049 if (likely (skb -> len ))
1050- goto out ;
1051-
1052- goto out_err ;
1050+ err = skb -> len ;
1051+ goto out ;
10531052 }
10541053 dumped = 1 ;
10551054next :
10561055 e ++ ;
10571056 }
10581057 }
10591058out :
1060- err = skb -> len ;
1061- out_err :
1062- rcu_read_unlock ();
10631059
10641060 cb -> args [1 ] = e ;
10651061 cb -> args [0 ] = h ;
10661062
1063+ unlock :
1064+ rcu_read_unlock ();
10671065 return err ;
10681066}
10691067
@@ -1666,5 +1664,6 @@ void __init ip_fib_init(void)
16661664
16671665 rtnl_register (PF_INET , RTM_NEWROUTE , inet_rtm_newroute , NULL , 0 );
16681666 rtnl_register (PF_INET , RTM_DELROUTE , inet_rtm_delroute , NULL , 0 );
1669- rtnl_register (PF_INET , RTM_GETROUTE , NULL , inet_dump_fib , 0 );
1667+ rtnl_register (PF_INET , RTM_GETROUTE , NULL , inet_dump_fib ,
1668+ RTNL_FLAG_DUMP_UNLOCKED );
16701669}
0 commit comments