@@ -623,23 +623,22 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
623623 struct rt6_rtnl_dump_arg arg = {
624624 .filter .dump_exceptions = true,
625625 .filter .dump_routes = true,
626- .filter .rtnl_held = true ,
626+ .filter .rtnl_held = false ,
627627 };
628628 const struct nlmsghdr * nlh = cb -> nlh ;
629629 struct net * net = sock_net (skb -> sk );
630- unsigned int h , s_h ;
631630 unsigned int e = 0 , s_e ;
631+ struct hlist_head * head ;
632632 struct fib6_walker * w ;
633633 struct fib6_table * tb ;
634- struct hlist_head * head ;
635- int res = 0 ;
634+ unsigned int h , s_h ;
635+ int err = 0 ;
636636
637+ rcu_read_lock ();
637638 if (cb -> strict_check ) {
638- int err ;
639-
640639 err = ip_valid_fib_dump_req (net , nlh , & arg .filter , cb );
641640 if (err < 0 )
642- return err ;
641+ goto unlock ;
643642 } else if (nlmsg_len (nlh ) >= sizeof (struct rtmsg )) {
644643 struct rtmsg * rtm = nlmsg_data (nlh );
645644
@@ -660,8 +659,10 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
660659 * 2. allocate and initialize walker.
661660 */
662661 w = kzalloc (sizeof (* w ), GFP_ATOMIC );
663- if (!w )
664- return - ENOMEM ;
662+ if (!w ) {
663+ err = - ENOMEM ;
664+ goto unlock ;
665+ }
665666 w -> func = fib6_dump_node ;
666667 cb -> args [2 ] = (long )w ;
667668 }
@@ -675,46 +676,46 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
675676 tb = fib6_get_table (net , arg .filter .table_id );
676677 if (!tb ) {
677678 if (rtnl_msg_family (cb -> nlh ) != PF_INET6 )
678- goto out ;
679+ goto unlock ;
679680
680681 NL_SET_ERR_MSG_MOD (cb -> extack , "FIB table does not exist" );
681- return - ENOENT ;
682+ err = - ENOENT ;
683+ goto unlock ;
682684 }
683685
684686 if (!cb -> args [0 ]) {
685- res = fib6_dump_table (tb , skb , cb );
686- if (!res )
687+ err = fib6_dump_table (tb , skb , cb );
688+ if (!err )
687689 cb -> args [0 ] = 1 ;
688690 }
689- goto out ;
691+ goto unlock ;
690692 }
691693
692694 s_h = cb -> args [0 ];
693695 s_e = cb -> args [1 ];
694696
695- rcu_read_lock ();
696697 for (h = s_h ; h < FIB6_TABLE_HASHSZ ; h ++ , s_e = 0 ) {
697698 e = 0 ;
698699 head = & net -> ipv6 .fib_table_hash [h ];
699700 hlist_for_each_entry_rcu (tb , head , tb6_hlist ) {
700701 if (e < s_e )
701702 goto next ;
702- res = fib6_dump_table (tb , skb , cb );
703- if (res != 0 )
704- goto out_unlock ;
703+ err = fib6_dump_table (tb , skb , cb );
704+ if (err != 0 )
705+ goto out ;
705706next :
706707 e ++ ;
707708 }
708709 }
709- out_unlock :
710- rcu_read_unlock ();
710+ out :
711711 cb -> args [1 ] = e ;
712712 cb -> args [0 ] = h ;
713- out :
714- res = res < 0 ? res : skb -> len ;
715- if (res <= 0 )
713+
714+ unlock :
715+ rcu_read_unlock ();
716+ if (err <= 0 )
716717 fib6_dump_end (cb );
717- return res ;
718+ return err ;
718719}
719720
720721void fib6_metric_set (struct fib6_info * f6i , int metric , u32 val )
@@ -2506,7 +2507,7 @@ int __init fib6_init(void)
25062507 goto out_kmem_cache_create ;
25072508
25082509 ret = rtnl_register_module (THIS_MODULE , PF_INET6 , RTM_GETROUTE , NULL ,
2509- inet6_dump_fib , 0 );
2510+ inet6_dump_fib , RTNL_FLAG_DUMP_UNLOCKED );
25102511 if (ret )
25112512 goto out_unregister_subsys ;
25122513
0 commit comments