diff options
-rw-r--r-- | net/batman-adv/hard-interface.c | 24 | ||||
-rw-r--r-- | net/batman-adv/soft-interface.c | 32 | ||||
-rw-r--r-- | net/batman-adv/types.h | 6 |
3 files changed, 57 insertions, 5 deletions
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index f1d37cd81815..cb3191fe60fc 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
@@ -457,6 +457,24 @@ out: | |||
457 | batadv_hardif_free_ref(primary_if); | 457 | batadv_hardif_free_ref(primary_if); |
458 | } | 458 | } |
459 | 459 | ||
460 | /** | ||
461 | * batadv_hardif_remove_interface_finish - cleans up the remains of a hardif | ||
462 | * @work: work queue item | ||
463 | * | ||
464 | * Free the parts of the hard interface which can not be removed under | ||
465 | * rtnl lock (to prevent deadlock situations). | ||
466 | */ | ||
467 | static void batadv_hardif_remove_interface_finish(struct work_struct *work) | ||
468 | { | ||
469 | struct batadv_hard_iface *hard_iface; | ||
470 | |||
471 | hard_iface = container_of(work, struct batadv_hard_iface, | ||
472 | cleanup_work); | ||
473 | |||
474 | batadv_sysfs_del_hardif(&hard_iface->hardif_obj); | ||
475 | batadv_hardif_free_ref(hard_iface); | ||
476 | } | ||
477 | |||
460 | static struct batadv_hard_iface * | 478 | static struct batadv_hard_iface * |
461 | batadv_hardif_add_interface(struct net_device *net_dev) | 479 | batadv_hardif_add_interface(struct net_device *net_dev) |
462 | { | 480 | { |
@@ -484,6 +502,9 @@ batadv_hardif_add_interface(struct net_device *net_dev) | |||
484 | hard_iface->soft_iface = NULL; | 502 | hard_iface->soft_iface = NULL; |
485 | hard_iface->if_status = BATADV_IF_NOT_IN_USE; | 503 | hard_iface->if_status = BATADV_IF_NOT_IN_USE; |
486 | INIT_LIST_HEAD(&hard_iface->list); | 504 | INIT_LIST_HEAD(&hard_iface->list); |
505 | INIT_WORK(&hard_iface->cleanup_work, | ||
506 | batadv_hardif_remove_interface_finish); | ||
507 | |||
487 | /* extra reference for return */ | 508 | /* extra reference for return */ |
488 | atomic_set(&hard_iface->refcount, 2); | 509 | atomic_set(&hard_iface->refcount, 2); |
489 | 510 | ||
@@ -518,8 +539,7 @@ static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface) | |||
518 | return; | 539 | return; |
519 | 540 | ||
520 | hard_iface->if_status = BATADV_IF_TO_BE_REMOVED; | 541 | hard_iface->if_status = BATADV_IF_TO_BE_REMOVED; |
521 | batadv_sysfs_del_hardif(&hard_iface->hardif_obj); | 542 | queue_work(batadv_event_workqueue, &hard_iface->cleanup_work); |
522 | batadv_hardif_free_ref(hard_iface); | ||
523 | } | 543 | } |
524 | 544 | ||
525 | void batadv_hardif_remove_interfaces(void) | 545 | void batadv_hardif_remove_interfaces(void) |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 3d6816667bfc..c9962fee44b1 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -449,6 +449,30 @@ static void batadv_interface_setup(struct net_device *dev) | |||
449 | memset(priv, 0, sizeof(*priv)); | 449 | memset(priv, 0, sizeof(*priv)); |
450 | } | 450 | } |
451 | 451 | ||
452 | /** | ||
453 | * batadv_softif_destroy_finish - cleans up the remains of a softif | ||
454 | * @work: work queue item | ||
455 | * | ||
456 | * Free the parts of the soft interface which can not be removed under | ||
457 | * rtnl lock (to prevent deadlock situations). | ||
458 | */ | ||
459 | static void batadv_softif_destroy_finish(struct work_struct *work) | ||
460 | { | ||
461 | struct batadv_priv *bat_priv; | ||
462 | struct net_device *soft_iface; | ||
463 | |||
464 | bat_priv = container_of(work, struct batadv_priv, | ||
465 | cleanup_work); | ||
466 | soft_iface = bat_priv->soft_iface; | ||
467 | |||
468 | batadv_debugfs_del_meshif(soft_iface); | ||
469 | batadv_sysfs_del_meshif(soft_iface); | ||
470 | |||
471 | rtnl_lock(); | ||
472 | unregister_netdevice(soft_iface); | ||
473 | rtnl_unlock(); | ||
474 | } | ||
475 | |||
452 | struct net_device *batadv_softif_create(const char *name) | 476 | struct net_device *batadv_softif_create(const char *name) |
453 | { | 477 | { |
454 | struct net_device *soft_iface; | 478 | struct net_device *soft_iface; |
@@ -463,6 +487,8 @@ struct net_device *batadv_softif_create(const char *name) | |||
463 | goto out; | 487 | goto out; |
464 | 488 | ||
465 | bat_priv = netdev_priv(soft_iface); | 489 | bat_priv = netdev_priv(soft_iface); |
490 | bat_priv->soft_iface = soft_iface; | ||
491 | INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish); | ||
466 | 492 | ||
467 | /* batadv_interface_stats() needs to be available as soon as | 493 | /* batadv_interface_stats() needs to be available as soon as |
468 | * register_netdevice() has been called | 494 | * register_netdevice() has been called |
@@ -551,10 +577,10 @@ out: | |||
551 | 577 | ||
552 | void batadv_softif_destroy(struct net_device *soft_iface) | 578 | void batadv_softif_destroy(struct net_device *soft_iface) |
553 | { | 579 | { |
554 | batadv_debugfs_del_meshif(soft_iface); | 580 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
555 | batadv_sysfs_del_meshif(soft_iface); | 581 | |
556 | batadv_mesh_free(soft_iface); | 582 | batadv_mesh_free(soft_iface); |
557 | unregister_netdevice(soft_iface); | 583 | queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); |
558 | } | 584 | } |
559 | 585 | ||
560 | int batadv_softif_is_valid(const struct net_device *net_dev) | 586 | int batadv_softif_is_valid(const struct net_device *net_dev) |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 03197f5ebf6c..8d4a16c0ed50 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -68,6 +68,7 @@ struct batadv_hard_iface_bat_iv { | |||
68 | * @soft_iface: the batman-adv interface which uses this network interface | 68 | * @soft_iface: the batman-adv interface which uses this network interface |
69 | * @rcu: struct used for freeing in an RCU-safe manner | 69 | * @rcu: struct used for freeing in an RCU-safe manner |
70 | * @bat_iv: BATMAN IV specific per hard interface data | 70 | * @bat_iv: BATMAN IV specific per hard interface data |
71 | * @cleanup_work: work queue callback item for hard interface deinit | ||
71 | */ | 72 | */ |
72 | struct batadv_hard_iface { | 73 | struct batadv_hard_iface { |
73 | struct list_head list; | 74 | struct list_head list; |
@@ -81,6 +82,7 @@ struct batadv_hard_iface { | |||
81 | struct net_device *soft_iface; | 82 | struct net_device *soft_iface; |
82 | struct rcu_head rcu; | 83 | struct rcu_head rcu; |
83 | struct batadv_hard_iface_bat_iv bat_iv; | 84 | struct batadv_hard_iface_bat_iv bat_iv; |
85 | struct work_struct cleanup_work; | ||
84 | }; | 86 | }; |
85 | 87 | ||
86 | /** | 88 | /** |
@@ -428,6 +430,7 @@ struct batadv_priv_dat { | |||
428 | /** | 430 | /** |
429 | * struct batadv_priv - per mesh interface data | 431 | * struct batadv_priv - per mesh interface data |
430 | * @mesh_state: current status of the mesh (inactive/active/deactivating) | 432 | * @mesh_state: current status of the mesh (inactive/active/deactivating) |
433 | * @soft_iface: net device which holds this struct as private data | ||
431 | * @stats: structure holding the data for the ndo_get_stats() call | 434 | * @stats: structure holding the data for the ndo_get_stats() call |
432 | * @bat_counters: mesh internal traffic statistic counters (see batadv_counters) | 435 | * @bat_counters: mesh internal traffic statistic counters (see batadv_counters) |
433 | * @aggregated_ogms: bool indicating whether OGM aggregation is enabled | 436 | * @aggregated_ogms: bool indicating whether OGM aggregation is enabled |
@@ -457,6 +460,7 @@ struct batadv_priv_dat { | |||
457 | * @forw_bat_list_lock: lock protecting forw_bat_list | 460 | * @forw_bat_list_lock: lock protecting forw_bat_list |
458 | * @forw_bcast_list_lock: lock protecting forw_bcast_list | 461 | * @forw_bcast_list_lock: lock protecting forw_bcast_list |
459 | * @orig_work: work queue callback item for orig node purging | 462 | * @orig_work: work queue callback item for orig node purging |
463 | * @cleanup_work: work queue callback item for soft interface deinit | ||
460 | * @primary_if: one of the hard interfaces assigned to this mesh interface | 464 | * @primary_if: one of the hard interfaces assigned to this mesh interface |
461 | * becomes the primary interface | 465 | * becomes the primary interface |
462 | * @bat_algo_ops: routing algorithm used by this mesh interface | 466 | * @bat_algo_ops: routing algorithm used by this mesh interface |
@@ -469,6 +473,7 @@ struct batadv_priv_dat { | |||
469 | */ | 473 | */ |
470 | struct batadv_priv { | 474 | struct batadv_priv { |
471 | atomic_t mesh_state; | 475 | atomic_t mesh_state; |
476 | struct net_device *soft_iface; | ||
472 | struct net_device_stats stats; | 477 | struct net_device_stats stats; |
473 | uint64_t __percpu *bat_counters; /* Per cpu counters */ | 478 | uint64_t __percpu *bat_counters; /* Per cpu counters */ |
474 | atomic_t aggregated_ogms; | 479 | atomic_t aggregated_ogms; |
@@ -502,6 +507,7 @@ struct batadv_priv { | |||
502 | spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ | 507 | spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ |
503 | spinlock_t forw_bcast_list_lock; /* protects forw_bcast_list */ | 508 | spinlock_t forw_bcast_list_lock; /* protects forw_bcast_list */ |
504 | struct delayed_work orig_work; | 509 | struct delayed_work orig_work; |
510 | struct work_struct cleanup_work; | ||
505 | struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ | 511 | struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ |
506 | struct batadv_algo_ops *bat_algo_ops; | 512 | struct batadv_algo_ops *bat_algo_ops; |
507 | #ifdef CONFIG_BATMAN_ADV_BLA | 513 | #ifdef CONFIG_BATMAN_ADV_BLA |