3434#include <net/phonet/pn_dev.h>
3535
3636struct phonet_routes {
37- spinlock_t lock ;
37+ struct mutex lock ;
3838 struct net_device * table [64 ];
3939};
4040
@@ -248,17 +248,22 @@ static void phonet_route_autodel(struct net_device *dev)
248248
249249 /* Remove left-over Phonet routes */
250250 bitmap_zero (deleted , 64 );
251- spin_lock_bh (& pnn -> routes .lock );
251+ mutex_lock (& pnn -> routes .lock );
252252 for (i = 0 ; i < 64 ; i ++ )
253253 if (dev == pnn -> routes .table [i ]) {
254+ rcu_assign_pointer (pnn -> routes .table [i ], NULL );
254255 set_bit (i , deleted );
255- pnn -> routes .table [i ] = NULL ;
256- dev_put (dev );
257256 }
258- spin_unlock_bh (& pnn -> routes .lock );
257+ mutex_unlock (& pnn -> routes .lock );
258+
259+ if (bitmap_empty (deleted , 64 ))
260+ return ; /* short-circuit RCU */
261+ synchronize_rcu ();
259262 for (i = find_first_bit (deleted , 64 ); i < 64 ;
260- i = find_next_bit (deleted , 64 , i + 1 ))
263+ i = find_next_bit (deleted , 64 , i + 1 )) {
261264 rtm_phonet_notify (RTM_DELROUTE , dev , i );
265+ dev_put (dev );
266+ }
262267}
263268
264269/* notify Phonet of device events */
@@ -300,7 +305,7 @@ static int phonet_init_net(struct net *net)
300305
301306 INIT_LIST_HEAD (& pnn -> pndevs .list );
302307 spin_lock_init (& pnn -> pndevs .lock );
303- spin_lock_init (& pnn -> routes .lock );
308+ mutex_init (& pnn -> routes .lock );
304309 net_assign_generic (net , phonet_net_id , pnn );
305310 return 0 ;
306311}
@@ -361,31 +366,34 @@ int phonet_route_add(struct net_device *dev, u8 daddr)
361366 int err = - EEXIST ;
362367
363368 daddr = daddr >> 2 ;
364- spin_lock_bh (& routes -> lock );
369+ mutex_lock (& routes -> lock );
365370 if (routes -> table [daddr ] == NULL ) {
366- routes -> table [daddr ] = dev ;
371+ rcu_assign_pointer ( routes -> table [daddr ], dev ) ;
367372 dev_hold (dev );
368373 err = 0 ;
369374 }
370- spin_unlock_bh (& routes -> lock );
375+ mutex_unlock (& routes -> lock );
371376 return err ;
372377}
373378
374379int phonet_route_del (struct net_device * dev , u8 daddr )
375380{
376381 struct phonet_net * pnn = net_generic (dev_net (dev ), phonet_net_id );
377382 struct phonet_routes * routes = & pnn -> routes ;
378- int err = - ENOENT ;
379383
380384 daddr = daddr >> 2 ;
381- spin_lock_bh (& routes -> lock );
382- if (dev == routes -> table [daddr ]) {
383- routes -> table [daddr ] = NULL ;
384- dev_put (dev );
385- err = 0 ;
386- }
387- spin_unlock_bh (& routes -> lock );
388- return err ;
385+ mutex_lock (& routes -> lock );
386+ if (dev == routes -> table [daddr ])
387+ rcu_assign_pointer (routes -> table [daddr ], NULL );
388+ else
389+ dev = NULL ;
390+ mutex_unlock (& routes -> lock );
391+
392+ if (!dev )
393+ return - ENOENT ;
394+ synchronize_rcu ();
395+ dev_put (dev );
396+ return 0 ;
389397}
390398
391399struct net_device * phonet_route_get (struct net * net , u8 daddr )
@@ -397,9 +405,9 @@ struct net_device *phonet_route_get(struct net *net, u8 daddr)
397405 ASSERT_RTNL (); /* no need to hold the device */
398406
399407 daddr >>= 2 ;
400- spin_lock_bh ( & routes -> lock );
401- dev = routes -> table [daddr ];
402- spin_unlock_bh ( & routes -> lock );
408+ rcu_read_lock ( );
409+ dev = rcu_dereference ( routes -> table [daddr ]) ;
410+ rcu_read_unlock ( );
403411 return dev ;
404412}
405413
@@ -409,11 +417,12 @@ struct net_device *phonet_route_output(struct net *net, u8 daddr)
409417 struct phonet_routes * routes = & pnn -> routes ;
410418 struct net_device * dev ;
411419
412- spin_lock_bh (& routes -> lock );
413- dev = routes -> table [daddr >> 2 ];
420+ daddr >>= 2 ;
421+ rcu_read_lock ();
422+ dev = rcu_dereference (routes -> table [daddr ]);
414423 if (dev )
415424 dev_hold (dev );
416- spin_unlock_bh ( & routes -> lock );
425+ rcu_read_unlock ( );
417426
418427 if (!dev )
419428 dev = phonet_device_get (net ); /* Default route */
0 commit comments