diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-09-19 15:00:16 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-09-19 15:00:16 -0400 |
commit | b53d63ecce17c4ddf8636def9f6e8b865c3927f9 (patch) | |
tree | 683ef774fcfb423fa35f61e4326d0ce3f6a7c283 /net/mac80211/mesh_pathtbl.c | |
parent | 765cf9976e937f1cfe9159bf4534967c8bf8eb6d (diff) | |
parent | 12e62d6f7ec475e546b40bece2045da15d6c21ef (diff) |
Merge branch 'master' of ssh://infradead/~/public_git/wireless-next into for-davem
Diffstat (limited to 'net/mac80211/mesh_pathtbl.c')
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 192 |
1 files changed, 114 insertions, 78 deletions
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index f97d17cb073c..7f54c5042235 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <net/mac80211.h> | 16 | #include <net/mac80211.h> |
17 | #include "wme.h" | ||
17 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
18 | #include "mesh.h" | 19 | #include "mesh.h" |
19 | 20 | ||
@@ -48,8 +49,10 @@ static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ | |||
48 | int mesh_paths_generation; | 49 | int mesh_paths_generation; |
49 | 50 | ||
50 | /* This lock will have the grow table function as writer and add / delete nodes | 51 | /* This lock will have the grow table function as writer and add / delete nodes |
51 | * as readers. When reading the table (i.e. doing lookups) we are well protected | 52 | * as readers. RCU provides sufficient protection only when reading the table |
52 | * by RCU | 53 | * (i.e. doing lookups). Adding or adding or removing nodes requires we take |
54 | * the read lock or we risk operating on an old table. The write lock is only | ||
55 | * needed when modifying the number of buckets a table. | ||
53 | */ | 56 | */ |
54 | static DEFINE_RWLOCK(pathtbl_resize_lock); | 57 | static DEFINE_RWLOCK(pathtbl_resize_lock); |
55 | 58 | ||
@@ -210,6 +213,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | |||
210 | struct ieee80211_hdr *hdr; | 213 | struct ieee80211_hdr *hdr; |
211 | struct sk_buff_head tmpq; | 214 | struct sk_buff_head tmpq; |
212 | unsigned long flags; | 215 | unsigned long flags; |
216 | struct ieee80211_sub_if_data *sdata = mpath->sdata; | ||
213 | 217 | ||
214 | rcu_assign_pointer(mpath->next_hop, sta); | 218 | rcu_assign_pointer(mpath->next_hop, sta); |
215 | 219 | ||
@@ -220,6 +224,8 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | |||
220 | while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { | 224 | while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { |
221 | hdr = (struct ieee80211_hdr *) skb->data; | 225 | hdr = (struct ieee80211_hdr *) skb->data; |
222 | memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); | 226 | memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); |
227 | skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb)); | ||
228 | ieee80211_set_qos_hdr(sdata, skb); | ||
223 | __skb_queue_tail(&tmpq, skb); | 229 | __skb_queue_tail(&tmpq, skb); |
224 | } | 230 | } |
225 | 231 | ||
@@ -333,25 +339,14 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, | |||
333 | } | 339 | } |
334 | 340 | ||
335 | 341 | ||
336 | /** | 342 | static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst, |
337 | * mesh_path_lookup - look up a path in the mesh path table | 343 | struct ieee80211_sub_if_data *sdata) |
338 | * @dst: hardware address (ETH_ALEN length) of destination | ||
339 | * @sdata: local subif | ||
340 | * | ||
341 | * Returns: pointer to the mesh path structure, or NULL if not found | ||
342 | * | ||
343 | * Locking: must be called within a read rcu section. | ||
344 | */ | ||
345 | struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | ||
346 | { | 344 | { |
347 | struct mesh_path *mpath; | 345 | struct mesh_path *mpath; |
348 | struct hlist_node *n; | 346 | struct hlist_node *n; |
349 | struct hlist_head *bucket; | 347 | struct hlist_head *bucket; |
350 | struct mesh_table *tbl; | ||
351 | struct mpath_node *node; | 348 | struct mpath_node *node; |
352 | 349 | ||
353 | tbl = rcu_dereference(mesh_paths); | ||
354 | |||
355 | bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; | 350 | bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; |
356 | hlist_for_each_entry_rcu(node, n, bucket, list) { | 351 | hlist_for_each_entry_rcu(node, n, bucket, list) { |
357 | mpath = node->mpath; | 352 | mpath = node->mpath; |
@@ -359,8 +354,7 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
359 | memcmp(dst, mpath->dst, ETH_ALEN) == 0) { | 354 | memcmp(dst, mpath->dst, ETH_ALEN) == 0) { |
360 | if (MPATH_EXPIRED(mpath)) { | 355 | if (MPATH_EXPIRED(mpath)) { |
361 | spin_lock_bh(&mpath->state_lock); | 356 | spin_lock_bh(&mpath->state_lock); |
362 | if (MPATH_EXPIRED(mpath)) | 357 | mpath->flags &= ~MESH_PATH_ACTIVE; |
363 | mpath->flags &= ~MESH_PATH_ACTIVE; | ||
364 | spin_unlock_bh(&mpath->state_lock); | 358 | spin_unlock_bh(&mpath->state_lock); |
365 | } | 359 | } |
366 | return mpath; | 360 | return mpath; |
@@ -369,31 +363,23 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
369 | return NULL; | 363 | return NULL; |
370 | } | 364 | } |
371 | 365 | ||
372 | struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | 366 | /** |
367 | * mesh_path_lookup - look up a path in the mesh path table | ||
368 | * @dst: hardware address (ETH_ALEN length) of destination | ||
369 | * @sdata: local subif | ||
370 | * | ||
371 | * Returns: pointer to the mesh path structure, or NULL if not found | ||
372 | * | ||
373 | * Locking: must be called within a read rcu section. | ||
374 | */ | ||
375 | struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) | ||
373 | { | 376 | { |
374 | struct mesh_path *mpath; | 377 | return path_lookup(rcu_dereference(mesh_paths), dst, sdata); |
375 | struct hlist_node *n; | 378 | } |
376 | struct hlist_head *bucket; | ||
377 | struct mesh_table *tbl; | ||
378 | struct mpath_node *node; | ||
379 | |||
380 | tbl = rcu_dereference(mpp_paths); | ||
381 | 379 | ||
382 | bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; | 380 | struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) |
383 | hlist_for_each_entry_rcu(node, n, bucket, list) { | 381 | { |
384 | mpath = node->mpath; | 382 | return path_lookup(rcu_dereference(mpp_paths), dst, sdata); |
385 | if (mpath->sdata == sdata && | ||
386 | memcmp(dst, mpath->dst, ETH_ALEN) == 0) { | ||
387 | if (MPATH_EXPIRED(mpath)) { | ||
388 | spin_lock_bh(&mpath->state_lock); | ||
389 | if (MPATH_EXPIRED(mpath)) | ||
390 | mpath->flags &= ~MESH_PATH_ACTIVE; | ||
391 | spin_unlock_bh(&mpath->state_lock); | ||
392 | } | ||
393 | return mpath; | ||
394 | } | ||
395 | } | ||
396 | return NULL; | ||
397 | } | 383 | } |
398 | 384 | ||
399 | 385 | ||
@@ -420,8 +406,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data | |||
420 | if (j++ == idx) { | 406 | if (j++ == idx) { |
421 | if (MPATH_EXPIRED(node->mpath)) { | 407 | if (MPATH_EXPIRED(node->mpath)) { |
422 | spin_lock_bh(&node->mpath->state_lock); | 408 | spin_lock_bh(&node->mpath->state_lock); |
423 | if (MPATH_EXPIRED(node->mpath)) | 409 | node->mpath->flags &= ~MESH_PATH_ACTIVE; |
424 | node->mpath->flags &= ~MESH_PATH_ACTIVE; | ||
425 | spin_unlock_bh(&node->mpath->state_lock); | 410 | spin_unlock_bh(&node->mpath->state_lock); |
426 | } | 411 | } |
427 | return node->mpath; | 412 | return node->mpath; |
@@ -776,22 +761,47 @@ void mesh_plink_broken(struct sta_info *sta) | |||
776 | tbl = rcu_dereference(mesh_paths); | 761 | tbl = rcu_dereference(mesh_paths); |
777 | for_each_mesh_entry(tbl, p, node, i) { | 762 | for_each_mesh_entry(tbl, p, node, i) { |
778 | mpath = node->mpath; | 763 | mpath = node->mpath; |
779 | spin_lock_bh(&mpath->state_lock); | ||
780 | if (rcu_dereference(mpath->next_hop) == sta && | 764 | if (rcu_dereference(mpath->next_hop) == sta && |
781 | mpath->flags & MESH_PATH_ACTIVE && | 765 | mpath->flags & MESH_PATH_ACTIVE && |
782 | !(mpath->flags & MESH_PATH_FIXED)) { | 766 | !(mpath->flags & MESH_PATH_FIXED)) { |
767 | spin_lock_bh(&mpath->state_lock); | ||
783 | mpath->flags &= ~MESH_PATH_ACTIVE; | 768 | mpath->flags &= ~MESH_PATH_ACTIVE; |
784 | ++mpath->sn; | 769 | ++mpath->sn; |
785 | spin_unlock_bh(&mpath->state_lock); | 770 | spin_unlock_bh(&mpath->state_lock); |
786 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, | 771 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, |
787 | mpath->dst, cpu_to_le32(mpath->sn), | 772 | mpath->dst, cpu_to_le32(mpath->sn), |
788 | reason, bcast, sdata); | 773 | reason, bcast, sdata); |
789 | } else | 774 | } |
790 | spin_unlock_bh(&mpath->state_lock); | ||
791 | } | 775 | } |
792 | rcu_read_unlock(); | 776 | rcu_read_unlock(); |
793 | } | 777 | } |
794 | 778 | ||
779 | static void mesh_path_node_reclaim(struct rcu_head *rp) | ||
780 | { | ||
781 | struct mpath_node *node = container_of(rp, struct mpath_node, rcu); | ||
782 | struct ieee80211_sub_if_data *sdata = node->mpath->sdata; | ||
783 | |||
784 | del_timer_sync(&node->mpath->timer); | ||
785 | atomic_dec(&sdata->u.mesh.mpaths); | ||
786 | kfree(node->mpath); | ||
787 | kfree(node); | ||
788 | } | ||
789 | |||
790 | /* needs to be called with the corresponding hashwlock taken */ | ||
791 | static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) | ||
792 | { | ||
793 | struct mesh_path *mpath; | ||
794 | mpath = node->mpath; | ||
795 | spin_lock(&mpath->state_lock); | ||
796 | mpath->flags |= MESH_PATH_RESOLVING; | ||
797 | if (mpath->is_gate) | ||
798 | mesh_gate_del(tbl, mpath); | ||
799 | hlist_del_rcu(&node->list); | ||
800 | call_rcu(&node->rcu, mesh_path_node_reclaim); | ||
801 | spin_unlock(&mpath->state_lock); | ||
802 | atomic_dec(&tbl->entries); | ||
803 | } | ||
804 | |||
795 | /** | 805 | /** |
796 | * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches | 806 | * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches |
797 | * | 807 | * |
@@ -812,42 +822,59 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) | |||
812 | int i; | 822 | int i; |
813 | 823 | ||
814 | rcu_read_lock(); | 824 | rcu_read_lock(); |
815 | tbl = rcu_dereference(mesh_paths); | 825 | read_lock_bh(&pathtbl_resize_lock); |
826 | tbl = resize_dereference_mesh_paths(); | ||
816 | for_each_mesh_entry(tbl, p, node, i) { | 827 | for_each_mesh_entry(tbl, p, node, i) { |
817 | mpath = node->mpath; | 828 | mpath = node->mpath; |
818 | if (rcu_dereference(mpath->next_hop) == sta) | 829 | if (rcu_dereference(mpath->next_hop) == sta) { |
819 | mesh_path_del(mpath->dst, mpath->sdata); | 830 | spin_lock_bh(&tbl->hashwlock[i]); |
831 | __mesh_path_del(tbl, node); | ||
832 | spin_unlock_bh(&tbl->hashwlock[i]); | ||
833 | } | ||
820 | } | 834 | } |
835 | read_unlock_bh(&pathtbl_resize_lock); | ||
821 | rcu_read_unlock(); | 836 | rcu_read_unlock(); |
822 | } | 837 | } |
823 | 838 | ||
824 | void mesh_path_flush(struct ieee80211_sub_if_data *sdata) | 839 | static void table_flush_by_iface(struct mesh_table *tbl, |
840 | struct ieee80211_sub_if_data *sdata) | ||
825 | { | 841 | { |
826 | struct mesh_table *tbl; | ||
827 | struct mesh_path *mpath; | 842 | struct mesh_path *mpath; |
828 | struct mpath_node *node; | 843 | struct mpath_node *node; |
829 | struct hlist_node *p; | 844 | struct hlist_node *p; |
830 | int i; | 845 | int i; |
831 | 846 | ||
832 | rcu_read_lock(); | 847 | WARN_ON(!rcu_read_lock_held()); |
833 | tbl = rcu_dereference(mesh_paths); | ||
834 | for_each_mesh_entry(tbl, p, node, i) { | 848 | for_each_mesh_entry(tbl, p, node, i) { |
835 | mpath = node->mpath; | 849 | mpath = node->mpath; |
836 | if (mpath->sdata == sdata) | 850 | if (mpath->sdata != sdata) |
837 | mesh_path_del(mpath->dst, mpath->sdata); | 851 | continue; |
852 | spin_lock_bh(&tbl->hashwlock[i]); | ||
853 | __mesh_path_del(tbl, node); | ||
854 | spin_unlock_bh(&tbl->hashwlock[i]); | ||
838 | } | 855 | } |
839 | rcu_read_unlock(); | ||
840 | } | 856 | } |
841 | 857 | ||
842 | static void mesh_path_node_reclaim(struct rcu_head *rp) | 858 | /** |
859 | * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface | ||
860 | * | ||
861 | * This function deletes both mesh paths as well as mesh portal paths. | ||
862 | * | ||
863 | * @sdata - interface data to match | ||
864 | * | ||
865 | */ | ||
866 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) | ||
843 | { | 867 | { |
844 | struct mpath_node *node = container_of(rp, struct mpath_node, rcu); | 868 | struct mesh_table *tbl; |
845 | struct ieee80211_sub_if_data *sdata = node->mpath->sdata; | ||
846 | 869 | ||
847 | del_timer_sync(&node->mpath->timer); | 870 | rcu_read_lock(); |
848 | atomic_dec(&sdata->u.mesh.mpaths); | 871 | read_lock_bh(&pathtbl_resize_lock); |
849 | kfree(node->mpath); | 872 | tbl = resize_dereference_mesh_paths(); |
850 | kfree(node); | 873 | table_flush_by_iface(tbl, sdata); |
874 | tbl = resize_dereference_mpp_paths(); | ||
875 | table_flush_by_iface(tbl, sdata); | ||
876 | read_unlock_bh(&pathtbl_resize_lock); | ||
877 | rcu_read_unlock(); | ||
851 | } | 878 | } |
852 | 879 | ||
853 | /** | 880 | /** |
@@ -878,14 +905,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
878 | mpath = node->mpath; | 905 | mpath = node->mpath; |
879 | if (mpath->sdata == sdata && | 906 | if (mpath->sdata == sdata && |
880 | memcmp(addr, mpath->dst, ETH_ALEN) == 0) { | 907 | memcmp(addr, mpath->dst, ETH_ALEN) == 0) { |
881 | spin_lock_bh(&mpath->state_lock); | 908 | __mesh_path_del(tbl, node); |
882 | if (mpath->is_gate) | ||
883 | mesh_gate_del(tbl, mpath); | ||
884 | mpath->flags |= MESH_PATH_RESOLVING; | ||
885 | hlist_del_rcu(&node->list); | ||
886 | call_rcu(&node->rcu, mesh_path_node_reclaim); | ||
887 | atomic_dec(&tbl->entries); | ||
888 | spin_unlock_bh(&mpath->state_lock); | ||
889 | goto enddel; | 909 | goto enddel; |
890 | } | 910 | } |
891 | } | 911 | } |
@@ -991,9 +1011,14 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
991 | 1011 | ||
992 | da = hdr->addr3; | 1012 | da = hdr->addr3; |
993 | ra = hdr->addr1; | 1013 | ra = hdr->addr1; |
1014 | rcu_read_lock(); | ||
994 | mpath = mesh_path_lookup(da, sdata); | 1015 | mpath = mesh_path_lookup(da, sdata); |
995 | if (mpath) | 1016 | if (mpath) { |
1017 | spin_lock_bh(&mpath->state_lock); | ||
996 | sn = ++mpath->sn; | 1018 | sn = ++mpath->sn; |
1019 | spin_unlock_bh(&mpath->state_lock); | ||
1020 | } | ||
1021 | rcu_read_unlock(); | ||
997 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, | 1022 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, |
998 | cpu_to_le32(sn), reason, ra, sdata); | 1023 | cpu_to_le32(sn), reason, ra, sdata); |
999 | } | 1024 | } |
@@ -1074,6 +1099,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) | |||
1074 | int mesh_pathtbl_init(void) | 1099 | int mesh_pathtbl_init(void) |
1075 | { | 1100 | { |
1076 | struct mesh_table *tbl_path, *tbl_mpp; | 1101 | struct mesh_table *tbl_path, *tbl_mpp; |
1102 | int ret; | ||
1077 | 1103 | ||
1078 | tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); | 1104 | tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); |
1079 | if (!tbl_path) | 1105 | if (!tbl_path) |
@@ -1082,18 +1108,26 @@ int mesh_pathtbl_init(void) | |||
1082 | tbl_path->copy_node = &mesh_path_node_copy; | 1108 | tbl_path->copy_node = &mesh_path_node_copy; |
1083 | tbl_path->mean_chain_len = MEAN_CHAIN_LEN; | 1109 | tbl_path->mean_chain_len = MEAN_CHAIN_LEN; |
1084 | tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); | 1110 | tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); |
1111 | if (!tbl_path->known_gates) { | ||
1112 | ret = -ENOMEM; | ||
1113 | goto free_path; | ||
1114 | } | ||
1085 | INIT_HLIST_HEAD(tbl_path->known_gates); | 1115 | INIT_HLIST_HEAD(tbl_path->known_gates); |
1086 | 1116 | ||
1087 | 1117 | ||
1088 | tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); | 1118 | tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); |
1089 | if (!tbl_mpp) { | 1119 | if (!tbl_mpp) { |
1090 | mesh_table_free(tbl_path, true); | 1120 | ret = -ENOMEM; |
1091 | return -ENOMEM; | 1121 | goto free_path; |
1092 | } | 1122 | } |
1093 | tbl_mpp->free_node = &mesh_path_node_free; | 1123 | tbl_mpp->free_node = &mesh_path_node_free; |
1094 | tbl_mpp->copy_node = &mesh_path_node_copy; | 1124 | tbl_mpp->copy_node = &mesh_path_node_copy; |
1095 | tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN; | 1125 | tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN; |
1096 | tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); | 1126 | tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); |
1127 | if (!tbl_mpp->known_gates) { | ||
1128 | ret = -ENOMEM; | ||
1129 | goto free_mpp; | ||
1130 | } | ||
1097 | INIT_HLIST_HEAD(tbl_mpp->known_gates); | 1131 | INIT_HLIST_HEAD(tbl_mpp->known_gates); |
1098 | 1132 | ||
1099 | /* Need no locking since this is during init */ | 1133 | /* Need no locking since this is during init */ |
@@ -1101,6 +1135,12 @@ int mesh_pathtbl_init(void) | |||
1101 | RCU_INIT_POINTER(mpp_paths, tbl_mpp); | 1135 | RCU_INIT_POINTER(mpp_paths, tbl_mpp); |
1102 | 1136 | ||
1103 | return 0; | 1137 | return 0; |
1138 | |||
1139 | free_mpp: | ||
1140 | mesh_table_free(tbl_mpp, true); | ||
1141 | free_path: | ||
1142 | mesh_table_free(tbl_path, true); | ||
1143 | return ret; | ||
1104 | } | 1144 | } |
1105 | 1145 | ||
1106 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | 1146 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata) |
@@ -1117,14 +1157,10 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | |||
1117 | if (node->mpath->sdata != sdata) | 1157 | if (node->mpath->sdata != sdata) |
1118 | continue; | 1158 | continue; |
1119 | mpath = node->mpath; | 1159 | mpath = node->mpath; |
1120 | spin_lock_bh(&mpath->state_lock); | ||
1121 | if ((!(mpath->flags & MESH_PATH_RESOLVING)) && | 1160 | if ((!(mpath->flags & MESH_PATH_RESOLVING)) && |
1122 | (!(mpath->flags & MESH_PATH_FIXED)) && | 1161 | (!(mpath->flags & MESH_PATH_FIXED)) && |
1123 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) { | 1162 | time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) |
1124 | spin_unlock_bh(&mpath->state_lock); | ||
1125 | mesh_path_del(mpath->dst, mpath->sdata); | 1163 | mesh_path_del(mpath->dst, mpath->sdata); |
1126 | } else | ||
1127 | spin_unlock_bh(&mpath->state_lock); | ||
1128 | } | 1164 | } |
1129 | rcu_read_unlock(); | 1165 | rcu_read_unlock(); |
1130 | } | 1166 | } |