Commit 349eb8cf45aadd35836fdfde75b3265a01b2aaa1

Authored by Johannes Berg
Committed by John W. Linville
1 parent 1928ecab62

mac80211: annotate and fix RCU in mesh code

This adds proper RCU annotations to the mesh path
table code, and fixes a number of bugs in the code
that I found while checking the sparse warnings I
got as a result of the annotations.

Some things like the changes in mesh_path_add() or
mesh_pathtbl_init() only serve to shut up sparse,
but other changes like the changes surrounding the
for_each_mesh_entry() macro fix real RCU bugs in
the code.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

Showing 2 changed files with 102 additions and 56 deletions Side-by-side Diff

... ... @@ -289,10 +289,6 @@
289 289 return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
290 290 }
291 291  
292   -#define for_each_mesh_entry(x, p, node, i) \
293   - for (i = 0; i <= x->hash_mask; i++) \
294   - hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
295   -
296 292 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
297 293  
298 294 void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
net/mac80211/mesh_pathtbl.c
... ... @@ -36,8 +36,8 @@
36 36 struct mesh_path *mpath;
37 37 };
38 38  
39   -static struct mesh_table *mesh_paths;
40   -static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
  39 +static struct mesh_table __rcu *mesh_paths;
  40 +static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
41 41  
42 42 int mesh_paths_generation;
43 43  
... ... @@ -48,6 +48,29 @@
48 48 static DEFINE_RWLOCK(pathtbl_resize_lock);
49 49  
50 50  
  51 +static inline struct mesh_table *resize_dereference_mesh_paths(void)
  52 +{
  53 + return rcu_dereference_protected(mesh_paths,
  54 + lockdep_is_held(&pathtbl_resize_lock));
  55 +}
  56 +
  57 +static inline struct mesh_table *resize_dereference_mpp_paths(void)
  58 +{
  59 + return rcu_dereference_protected(mpp_paths,
  60 + lockdep_is_held(&pathtbl_resize_lock));
  61 +}
  62 +
  63 +/*
  64 + * CAREFUL -- "tbl" must not be an expression,
  65 + * in particular not an rcu_dereference(), since
  66 + * it's used twice. So it is illegal to do
  67 + * for_each_mesh_entry(rcu_dereference(...), ...)
  68 + */
  69 +#define for_each_mesh_entry(tbl, p, node, i) \
  70 + for (i = 0; i <= tbl->hash_mask; i++) \
  71 + hlist_for_each_entry_rcu(node, p, &tbl->hash_buckets[i], list)
  72 +
  73 +
51 74 static struct mesh_table *mesh_table_alloc(int size_order)
52 75 {
53 76 int i;
54 77  
... ... @@ -258,12 +281,13 @@
258 281 */
259 282 struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata)
260 283 {
  284 + struct mesh_table *tbl = rcu_dereference(mesh_paths);
261 285 struct mpath_node *node;
262 286 struct hlist_node *p;
263 287 int i;
264 288 int j = 0;
265 289  
266   - for_each_mesh_entry(mesh_paths, p, node, i) {
  290 + for_each_mesh_entry(tbl, p, node, i) {
267 291 if (sdata && node->mpath->sdata != sdata)
268 292 continue;
269 293 if (j++ == idx) {
... ... @@ -293,6 +317,7 @@
293 317 {
294 318 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
295 319 struct ieee80211_local *local = sdata->local;
  320 + struct mesh_table *tbl;
296 321 struct mesh_path *mpath, *new_mpath;
297 322 struct mpath_node *node, *new_node;
298 323 struct hlist_head *bucket;
299 324  
300 325  
... ... @@ -332,11 +357,13 @@
332 357 spin_lock_init(&new_mpath->state_lock);
333 358 init_timer(&new_mpath->timer);
334 359  
335   - hash_idx = mesh_table_hash(dst, sdata, mesh_paths);
336   - bucket = &mesh_paths->hash_buckets[hash_idx];
  360 + tbl = resize_dereference_mesh_paths();
337 361  
338   - spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
  362 + hash_idx = mesh_table_hash(dst, sdata, tbl);
  363 + bucket = &tbl->hash_buckets[hash_idx];
339 364  
  365 + spin_lock_bh(&tbl->hashwlock[hash_idx]);
  366 +
340 367 err = -EEXIST;
341 368 hlist_for_each_entry(node, n, bucket, list) {
342 369 mpath = node->mpath;
343 370  
... ... @@ -345,13 +372,13 @@
345 372 }
346 373  
347 374 hlist_add_head_rcu(&new_node->list, bucket);
348   - if (atomic_inc_return(&mesh_paths->entries) >=
349   - mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
  375 + if (atomic_inc_return(&tbl->entries) >=
  376 + tbl->mean_chain_len * (tbl->hash_mask + 1))
350 377 grow = 1;
351 378  
352 379 mesh_paths_generation++;
353 380  
354   - spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
  381 + spin_unlock_bh(&tbl->hashwlock[hash_idx]);
355 382 read_unlock_bh(&pathtbl_resize_lock);
356 383 if (grow) {
357 384 set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags);
... ... @@ -360,7 +387,7 @@
360 387 return 0;
361 388  
362 389 err_exists:
363   - spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
  390 + spin_unlock_bh(&tbl->hashwlock[hash_idx]);
364 391 read_unlock_bh(&pathtbl_resize_lock);
365 392 kfree(new_node);
366 393 err_node_alloc:
367 394  
... ... @@ -382,11 +409,11 @@
382 409 struct mesh_table *oldtbl, *newtbl;
383 410  
384 411 write_lock_bh(&pathtbl_resize_lock);
385   - newtbl = mesh_table_alloc(mesh_paths->size_order + 1);
  412 + oldtbl = resize_dereference_mesh_paths();
  413 + newtbl = mesh_table_alloc(oldtbl->size_order + 1);
386 414 if (!newtbl)
387 415 goto out;
388   - oldtbl = mesh_paths;
389   - if (mesh_table_grow(mesh_paths, newtbl) < 0) {
  416 + if (mesh_table_grow(oldtbl, newtbl) < 0) {
390 417 __mesh_table_free(newtbl);
391 418 goto out;
392 419 }
393 420  
... ... @@ -403,11 +430,11 @@
403 430 struct mesh_table *oldtbl, *newtbl;
404 431  
405 432 write_lock_bh(&pathtbl_resize_lock);
406   - newtbl = mesh_table_alloc(mpp_paths->size_order + 1);
  433 + oldtbl = resize_dereference_mpp_paths();
  434 + newtbl = mesh_table_alloc(oldtbl->size_order + 1);
407 435 if (!newtbl)
408 436 goto out;
409   - oldtbl = mpp_paths;
410   - if (mesh_table_grow(mpp_paths, newtbl) < 0) {
  437 + if (mesh_table_grow(oldtbl, newtbl) < 0) {
411 438 __mesh_table_free(newtbl);
412 439 goto out;
413 440 }
... ... @@ -422,6 +449,7 @@
422 449 {
423 450 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
424 451 struct ieee80211_local *local = sdata->local;
  452 + struct mesh_table *tbl;
425 453 struct mesh_path *mpath, *new_mpath;
426 454 struct mpath_node *node, *new_node;
427 455 struct hlist_head *bucket;
428 456  
429 457  
... ... @@ -456,11 +484,13 @@
456 484 new_mpath->exp_time = jiffies;
457 485 spin_lock_init(&new_mpath->state_lock);
458 486  
459   - hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
460   - bucket = &mpp_paths->hash_buckets[hash_idx];
  487 + tbl = resize_dereference_mpp_paths();
461 488  
462   - spin_lock_bh(&mpp_paths->hashwlock[hash_idx]);
  489 + hash_idx = mesh_table_hash(dst, sdata, tbl);
  490 + bucket = &tbl->hash_buckets[hash_idx];
463 491  
  492 + spin_lock_bh(&tbl->hashwlock[hash_idx]);
  493 +
464 494 err = -EEXIST;
465 495 hlist_for_each_entry(node, n, bucket, list) {
466 496 mpath = node->mpath;
467 497  
... ... @@ -469,11 +499,11 @@
469 499 }
470 500  
471 501 hlist_add_head_rcu(&new_node->list, bucket);
472   - if (atomic_inc_return(&mpp_paths->entries) >=
473   - mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
  502 + if (atomic_inc_return(&tbl->entries) >=
  503 + tbl->mean_chain_len * (tbl->hash_mask + 1))
474 504 grow = 1;
475 505  
476   - spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
  506 + spin_unlock_bh(&tbl->hashwlock[hash_idx]);
477 507 read_unlock_bh(&pathtbl_resize_lock);
478 508 if (grow) {
479 509 set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
... ... @@ -482,7 +512,7 @@
482 512 return 0;
483 513  
484 514 err_exists:
485   - spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
  515 + spin_unlock_bh(&tbl->hashwlock[hash_idx]);
486 516 read_unlock_bh(&pathtbl_resize_lock);
487 517 kfree(new_node);
488 518 err_node_alloc:
... ... @@ -502,6 +532,7 @@
502 532 */
503 533 void mesh_plink_broken(struct sta_info *sta)
504 534 {
  535 + struct mesh_table *tbl;
505 536 static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
506 537 struct mesh_path *mpath;
507 538 struct mpath_node *node;
508 539  
... ... @@ -510,10 +541,11 @@
510 541 int i;
511 542  
512 543 rcu_read_lock();
513   - for_each_mesh_entry(mesh_paths, p, node, i) {
  544 + tbl = rcu_dereference(mesh_paths);
  545 + for_each_mesh_entry(tbl, p, node, i) {
514 546 mpath = node->mpath;
515 547 spin_lock_bh(&mpath->state_lock);
516   - if (mpath->next_hop == sta &&
  548 + if (rcu_dereference(mpath->next_hop) == sta &&
517 549 mpath->flags & MESH_PATH_ACTIVE &&
518 550 !(mpath->flags & MESH_PATH_FIXED)) {
519 551 mpath->flags &= ~MESH_PATH_ACTIVE;
520 552  
521 553  
522 554  
523 555  
524 556  
525 557  
... ... @@ -542,30 +574,38 @@
542 574 */
543 575 void mesh_path_flush_by_nexthop(struct sta_info *sta)
544 576 {
  577 + struct mesh_table *tbl;
545 578 struct mesh_path *mpath;
546 579 struct mpath_node *node;
547 580 struct hlist_node *p;
548 581 int i;
549 582  
550   - for_each_mesh_entry(mesh_paths, p, node, i) {
  583 + rcu_read_lock();
  584 + tbl = rcu_dereference(mesh_paths);
  585 + for_each_mesh_entry(tbl, p, node, i) {
551 586 mpath = node->mpath;
552   - if (mpath->next_hop == sta)
  587 + if (rcu_dereference(mpath->next_hop) == sta)
553 588 mesh_path_del(mpath->dst, mpath->sdata);
554 589 }
  590 + rcu_read_unlock();
555 591 }
556 592  
557 593 void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
558 594 {
  595 + struct mesh_table *tbl;
559 596 struct mesh_path *mpath;
560 597 struct mpath_node *node;
561 598 struct hlist_node *p;
562 599 int i;
563 600  
564   - for_each_mesh_entry(mesh_paths, p, node, i) {
  601 + rcu_read_lock();
  602 + tbl = rcu_dereference(mesh_paths);
  603 + for_each_mesh_entry(tbl, p, node, i) {
565 604 mpath = node->mpath;
566 605 if (mpath->sdata == sdata)
567 606 mesh_path_del(mpath->dst, mpath->sdata);
568 607 }
  608 + rcu_read_unlock();
569 609 }
570 610  
571 611 static void mesh_path_node_reclaim(struct rcu_head *rp)
... ... @@ -589,6 +629,7 @@
589 629 */
590 630 int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
591 631 {
  632 + struct mesh_table *tbl;
592 633 struct mesh_path *mpath;
593 634 struct mpath_node *node;
594 635 struct hlist_head *bucket;
595 636  
596 637  
597 638  
... ... @@ -597,19 +638,20 @@
597 638 int err = 0;
598 639  
599 640 read_lock_bh(&pathtbl_resize_lock);
600   - hash_idx = mesh_table_hash(addr, sdata, mesh_paths);
601   - bucket = &mesh_paths->hash_buckets[hash_idx];
  641 + tbl = resize_dereference_mesh_paths();
  642 + hash_idx = mesh_table_hash(addr, sdata, tbl);
  643 + bucket = &tbl->hash_buckets[hash_idx];
602 644  
603   - spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
  645 + spin_lock_bh(&tbl->hashwlock[hash_idx]);
604 646 hlist_for_each_entry(node, n, bucket, list) {
605 647 mpath = node->mpath;
606 648 if (mpath->sdata == sdata &&
607   - memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
  649 + memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
608 650 spin_lock_bh(&mpath->state_lock);
609 651 mpath->flags |= MESH_PATH_RESOLVING;
610 652 hlist_del_rcu(&node->list);
611 653 call_rcu(&node->rcu, mesh_path_node_reclaim);
612   - atomic_dec(&mesh_paths->entries);
  654 + atomic_dec(&tbl->entries);
613 655 spin_unlock_bh(&mpath->state_lock);
614 656 goto enddel;
615 657 }
... ... @@ -618,7 +660,7 @@
618 660 err = -ENXIO;
619 661 enddel:
620 662 mesh_paths_generation++;
621   - spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
  663 + spin_unlock_bh(&tbl->hashwlock[hash_idx]);
622 664 read_unlock_bh(&pathtbl_resize_lock);
623 665 return err;
624 666 }
625 667  
626 668  
627 669  
628 670  
629 671  
630 672  
631 673  
632 674  
633 675  
... ... @@ -747,53 +789,61 @@
747 789  
748 790 int mesh_pathtbl_init(void)
749 791 {
750   - mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
751   - if (!mesh_paths)
  792 + struct mesh_table *tbl_path, *tbl_mpp;
  793 +
  794 + tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
  795 + if (!tbl_path)
752 796 return -ENOMEM;
753   - mesh_paths->free_node = &mesh_path_node_free;
754   - mesh_paths->copy_node = &mesh_path_node_copy;
755   - mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
  797 + tbl_path->free_node = &mesh_path_node_free;
  798 + tbl_path->copy_node = &mesh_path_node_copy;
  799 + tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
756 800  
757   - mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
758   - if (!mpp_paths) {
759   - mesh_table_free(mesh_paths, true);
  801 + tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
  802 + if (!tbl_mpp) {
  803 + mesh_table_free(tbl_path, true);
760 804 return -ENOMEM;
761 805 }
762   - mpp_paths->free_node = &mesh_path_node_free;
763   - mpp_paths->copy_node = &mesh_path_node_copy;
764   - mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
  806 + tbl_mpp->free_node = &mesh_path_node_free;
  807 + tbl_mpp->copy_node = &mesh_path_node_copy;
  808 + tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
765 809  
  810 + /* Need no locking since this is during init */
  811 + RCU_INIT_POINTER(mesh_paths, tbl_path);
  812 + RCU_INIT_POINTER(mpp_paths, tbl_mpp);
  813 +
766 814 return 0;
767 815 }
768 816  
769 817 void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
770 818 {
  819 + struct mesh_table *tbl;
771 820 struct mesh_path *mpath;
772 821 struct mpath_node *node;
773 822 struct hlist_node *p;
774 823 int i;
775 824  
776   - read_lock_bh(&pathtbl_resize_lock);
777   - for_each_mesh_entry(mesh_paths, p, node, i) {
  825 + rcu_read_lock();
  826 + tbl = rcu_dereference(mesh_paths);
  827 + for_each_mesh_entry(tbl, p, node, i) {
778 828 if (node->mpath->sdata != sdata)
779 829 continue;
780 830 mpath = node->mpath;
781 831 spin_lock_bh(&mpath->state_lock);
782 832 if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
783 833 (!(mpath->flags & MESH_PATH_FIXED)) &&
784   - time_after(jiffies,
785   - mpath->exp_time + MESH_PATH_EXPIRE)) {
  834 + time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) {
786 835 spin_unlock_bh(&mpath->state_lock);
787 836 mesh_path_del(mpath->dst, mpath->sdata);
788 837 } else
789 838 spin_unlock_bh(&mpath->state_lock);
790 839 }
791   - read_unlock_bh(&pathtbl_resize_lock);
  840 + rcu_read_unlock();
792 841 }
793 842  
794 843 void mesh_pathtbl_unregister(void)
795 844 {
796   - mesh_table_free(mesh_paths, true);
797   - mesh_table_free(mpp_paths, true);
  845 + /* no need for locking during exit path */
  846 + mesh_table_free(rcu_dereference_raw(mesh_paths), true);
  847 + mesh_table_free(rcu_dereference_raw(mpp_paths), true);
798 848 }