| @@ -20,8 +20,9 @@ static unsigned __read_mostly afs_cell_min_ttl = 10 * 60; · 19 unmodified lines |
| 20 | static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60; | 20 | static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60; |
| 21 | static atomic_t cell_debug_id; | 21 | static atomic_t cell_debug_id; |
| 22 | | 22 | |
| 23 | static void afs_queue_cell_manager(struct afs_net *); | 23 | static void afs_cell_timer(struct timer_list *timer); |
| 24 | static void afs_manage_cell_work(struct work_struct *); | 24 | static void afs_destroy_cell_work(struct work_struct *work); |
| | 25 | static void afs_manage_cell_work(struct work_struct *work); |
| 25 | | 26 | |
| 26 | static void afs_dec_cells_outstanding(struct afs_net *net) | 27 | static void afs_dec_cells_outstanding(struct afs_net *net) |
| 27 | { | 28 | { |
| @@ -29,19 +30,11 @@ static void afs_dec_cells_outstanding(struct afs_net *net) · 1 unmodified line |
| 29 | wake_up_var(&net->cells_outstanding); | 30 | wake_up_var(&net->cells_outstanding); |
| 30 | } | 31 | } |
| 31 | | 32 | |
| 32 | /* | 33 | static void afs_set_cell_state(struct afs_cell *cell, enum afs_cell_state state) |
| 33 | * Set the cell timer to fire after a given delay, assuming it's not already | | |
| 34 | * set for an earlier time. | | |
| 35 | */ | | |
| 36 | static void afs_set_cell_timer(struct afs_net *net, time64_t delay) | | |
| 37 | { | 34 | { |
| 38 | if (net->live) { | 35 | smp_store_release(&cell->state, state); /* Commit cell changes before state */ |
| 39 | atomic_inc(&net->cells_outstanding); | 36 | smp_wmb(); /* Set cell state before task state */ |
| 40 | if (timer_reduce(&net->cells_timer, jiffies + delay * HZ)) | 37 | wake_up_var(&cell->state); |
| 41 | afs_dec_cells_outstanding(net); | | |
| 42 | } else { | | |
| 43 | afs_queue_cell_manager(net); | | |
| 44 | } | | |
| 45 | } | 38 | } |
| 46 | | 39 | |
| 47 | /* | 40 | /* |
| @@ -116,7 +109,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, · 68 unmodified lines |
| 116 | const char *name, unsigned int namelen, | 109 | const char *name, unsigned int namelen, |
| 117 | const char *addresses) | 110 | const char *addresses) |
| 118 | { | 111 | { |
| 119 | struct afs_vlserver_list *vllist; | 112 | struct afs_vlserver_list *vllist = NULL; |
| 120 | struct afs_cell *cell; | 113 | struct afs_cell *cell; |
| 121 | int i, ret; | 114 | int i, ret; |
| 122 | | 115 | |
| @@ -163,7 +156,9 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, · 40 unmodified lines |
| 163 | cell->net = net; | 156 | cell->net = net; |
| 164 | refcount_set(&cell->ref, 1); | 157 | refcount_set(&cell->ref, 1); |
| 165 | atomic_set(&cell->active, 0); | 158 | atomic_set(&cell->active, 0); |
| | 159 | INIT_WORK(&cell->destroyer, afs_destroy_cell_work); |
| 166 | INIT_WORK(&cell->manager, afs_manage_cell_work); | 160 | INIT_WORK(&cell->manager, afs_manage_cell_work); |
| | 161 | timer_setup(&cell->management_timer, afs_cell_timer, 0); |
| 167 | init_rwsem(&cell->vs_lock); | 162 | init_rwsem(&cell->vs_lock); |
| 168 | cell->volumes = RB_ROOT; | 163 | cell->volumes = RB_ROOT; |
| 169 | INIT_HLIST_HEAD(&cell->proc_volumes); | 164 | INIT_HLIST_HEAD(&cell->proc_volumes); |
| @@ -220,6 +215,7 @@ parse_failed: · 50 unmodified lines |
| 220 | if (ret == -EINVAL) | 215 | if (ret == -EINVAL) |
| 221 | printk(KERN_ERR "kAFS: bad VL server IP address\n"); | 216 | printk(KERN_ERR "kAFS: bad VL server IP address\n"); |
| 222 | error: | 217 | error: |
| | 218 | afs_put_vlserverlist(cell->net, vllist); |
| 223 | kfree(cell->name - 1); | 219 | kfree(cell->name - 1); |
| 224 | kfree(cell); | 220 | kfree(cell); |
| 225 | _leave(" = %d", ret); | 221 | _leave(" = %d", ret); |
| @@ -296,26 +292,28 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, · 70 unmodified lines |
| 296 | | 292 | |
| 297 | cell = candidate; | 293 | cell = candidate; |
| 298 | candidate = NULL; | 294 | candidate = NULL; |
| 299 | atomic_set(&cell->active, 2); | 295 | afs_use_cell(cell, trace); |
| 300 | trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 2, afs_cell_trace_insert); | | |
| 301 | rb_link_node_rcu(&cell->net_node, parent, pp); | 296 | rb_link_node_rcu(&cell->net_node, parent, pp); |
| 302 | rb_insert_color(&cell->net_node, &net->cells); | 297 | rb_insert_color(&cell->net_node, &net->cells); |
| 303 | up_write(&net->cells_lock); | 298 | up_write(&net->cells_lock); |
| 304 | | 299 | |
| 305 | afs_queue_cell(cell, afs_cell_trace_get_queue_new); | 300 | afs_queue_cell(cell, afs_cell_trace_queue_new); |
| 306 | | 301 | |
| 307 | wait_for_cell: | 302 | wait_for_cell: |
| 308 | trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), atomic_read(&cell->active), | | |
| 309 | afs_cell_trace_wait); | | |
| 310 | _debug("wait_for_cell"); | 303 | _debug("wait_for_cell"); |
| 311 | wait_var_event(&cell->state, | 304 | state = smp_load_acquire(&cell->state); /* vs error */ |
| 312 | ({ | 305 | if (state != AFS_CELL_ACTIVE && |
| 313 | state = smp_load_acquire(&cell->state); /* vs error */ | 306 | state != AFS_CELL_DEAD) { |
| 314 | state == AFS_CELL_ACTIVE || state == AFS_CELL_REMOVED; | 307 | afs_see_cell(cell, afs_cell_trace_wait); |
| 315 | })); | 308 | wait_var_event(&cell->state, |
| | 309 | ({ |
| | 310 | state = smp_load_acquire(&cell->state); /* vs error */ |
| | 311 | state == AFS_CELL_ACTIVE || state == AFS_CELL_DEAD; |
| | 312 | })); |
| | 313 | } |
| 316 | | 314 | |
| 317 | /* Check the state obtained from the wait check. */ | 315 | /* Check the state obtained from the wait check. */ |
| 318 | if (state == AFS_CELL_REMOVED) { | 316 | if (state == AFS_CELL_DEAD) { |
| 319 | ret = cell->error; | 317 | ret = cell->error; |
| 320 | goto error; | 318 | goto error; |
| 321 | } | 319 | } |
| @@ -397,7 +395,6 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) · 75 unmodified lines |
| 397 | | 395 | |
| 398 | /* install the new cell */ | 396 | /* install the new cell */ |
| 399 | down_write(&net->cells_lock); | 397 | down_write(&net->cells_lock); |
| 400 | afs_see_cell(new_root, afs_cell_trace_see_ws); | | |
| 401 | old_root = rcu_replace_pointer(net->ws_cell, new_root, | 398 | old_root = rcu_replace_pointer(net->ws_cell, new_root, |
| 402 | lockdep_is_held(&net->cells_lock)); | 399 | lockdep_is_held(&net->cells_lock)); |
| 403 | up_write(&net->cells_lock); | 400 | up_write(&net->cells_lock); |
| @@ -530,30 +527,14 @@ static void afs_cell_destroy(struct rcu_head *rcu) · 126 unmodified lines |
| 530 | _leave(" [destroyed]"); | 527 | _leave(" [destroyed]"); |
| 531 | } | 528 | } |
| 532 | | 529 | |
| 533 | /* | 530 | static void afs_destroy_cell_work(struct work_struct *work) |
| 534 | * Queue the cell manager. | | |
| 535 | */ | | |
| 536 | static void afs_queue_cell_manager(struct afs_net *net) | | |
| 537 | { | | |
| 538 | int outstanding = atomic_inc_return(&net->cells_outstanding); | | |
| 539 | | | |
| 540 | _enter("%d", outstanding); | | |
| 541 | | | |
| 542 | if (!queue_work(afs_wq, &net->cells_manager)) | | |
| 543 | afs_dec_cells_outstanding(net); | | |
| 544 | } | | |
| 545 | | | |
| 546 | /* | | |
| 547 | * Cell management timer. We have an increment on cells_outstanding that we | | |
| 548 | * need to pass along to the work item. | | |
| 549 | */ | | |
| 550 | void afs_cells_timer(struct timer_list *timer) | | |
| 551 | { | 531 | { |
| 552 | struct afs_net *net = container_of(timer, struct afs_net, cells_timer); | 532 | struct afs_cell *cell = container_of(work, struct afs_cell, destroyer); |
| 553 | | 533 | |
| 554 | _enter(""); | 534 | afs_see_cell(cell, afs_cell_trace_destroy); |
| 555 | if (!queue_work(afs_wq, &net->cells_manager)) | 535 | timer_delete_sync(&cell->management_timer); |
| 556 | afs_dec_cells_outstanding(net); | 536 | cancel_work_sync(&cell->manager); |
| | 537 | call_rcu(&cell->rcu, afs_cell_destroy); |
| 557 | } | 538 | } |
| 558 | | 539 | |
| 559 | /* | 540 | /* |
| @@ -585,7 +566,7 @@ void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason) · 25 unmodified lines |
| 585 | if (zero) { | 566 | if (zero) { |
| 586 | a = atomic_read(&cell->active); | 567 | a = atomic_read(&cell->active); |
| 587 | WARN(a != 0, "Cell active count %u > 0\n", a); | 568 | WARN(a != 0, "Cell active count %u > 0\n", a); |
| 588 | call_rcu(&cell->rcu, afs_cell_destroy); | 569 | WARN_ON(!queue_work(afs_wq, &cell->destroyer)); |
| 589 | } | 570 | } |
| 590 | } | 571 | } |
| 591 | } | 572 | } |
| @@ -597,10 +578,9 @@ struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason) · 5 unmodified lines |
| 597 | { | 578 | { |
| 598 | int r, a; | 579 | int r, a; |
| 599 | | 580 | |
| 600 | r = refcount_read(&cell->ref); | 581 | __refcount_inc(&cell->ref, &r); |
| 601 | WARN_ON(r == 0); | | |
| 602 | a = atomic_inc_return(&cell->active); | 582 | a = atomic_inc_return(&cell->active); |
| 603 | trace_afs_cell(cell->debug_id, r, a, reason); | 583 | trace_afs_cell(cell->debug_id, r + 1, a, reason); |
| 604 | return cell; | 584 | return cell; |
| 605 | } | 585 | } |
| 606 | | 586 | |
| @@ -612,6 +592,7 @@ void afs_unuse_cell(struct afs_cell *cell, enum afs_cell_trace reason) · 5 unmodified lines |
| 612 | { | 592 | { |
| 613 | unsigned int debug_id; | 593 | unsigned int debug_id; |
| 614 | time64_t now, expire_delay; | 594 | time64_t now, expire_delay; |
| | 595 | bool zero; |
| 615 | int r, a; | 596 | int r, a; |
| 616 | | 597 | |
| 617 | if (!cell) | 598 | if (!cell) |
| @@ -626,13 +607,15 @@ void afs_unuse_cell(struct afs_cell *cell, enum afs_cell_trace reason) · 8 unmodified lines |
| 626 | expire_delay = afs_cell_gc_delay; | 607 | expire_delay = afs_cell_gc_delay; |
| 627 | | 608 | |
| 628 | debug_id = cell->debug_id; | 609 | debug_id = cell->debug_id; |
| 629 | r = refcount_read(&cell->ref); | | |
| 630 | a = atomic_dec_return(&cell->active); | 610 | a = atomic_dec_return(&cell->active); |
| 631 | trace_afs_cell(debug_id, r, a, reason); | 611 | if (!a) |
| 632 | WARN_ON(a == 0); | | |
| 633 | if (a == 1) | | |
| 634 | /* 'cell' may now be garbage collected. */ | 612 | /* 'cell' may now be garbage collected. */ |
| 635 | afs_set_cell_timer(cell->net, expire_delay); | 613 | afs_set_cell_timer(cell, expire_delay); |
| | 614 | |
| | 615 | zero = __refcount_dec_and_test(&cell->ref, &r); |
| | 616 | trace_afs_cell(debug_id, r - 1, a, reason); |
| | 617 | if (zero) |
| | 618 | WARN_ON(!queue_work(afs_wq, &cell->destroyer)); |
| 636 | } | 619 | } |
| 637 | | 620 | |
| 638 | /* | 621 | /* |
| @@ -652,9 +635,27 @@ void afs_see_cell(struct afs_cell *cell, enum afs_cell_trace reason) · 13 unmodified lines |
| 652 | */ | 635 | */ |
| 653 | void afs_queue_cell(struct afs_cell *cell, enum afs_cell_trace reason) | 636 | void afs_queue_cell(struct afs_cell *cell, enum afs_cell_trace reason) |
| 654 | { | 637 | { |
| 655 | afs_get_cell(cell, reason); | 638 | queue_work(afs_wq, &cell->manager); |
| 656 | if (!queue_work(afs_wq, &cell->manager)) | 639 | } |
| 657 | afs_put_cell(cell, afs_cell_trace_put_queue_fail); | 640 | |
| | 641 | /* |
| | 642 | * Cell-specific management timer. |
| | 643 | */ |
| | 644 | static void afs_cell_timer(struct timer_list *timer) |
| | 645 | { |
| | 646 | struct afs_cell *cell = container_of(timer, struct afs_cell, management_timer); |
| | 647 | |
| | 648 | afs_see_cell(cell, afs_cell_trace_see_mgmt_timer); |
| | 649 | if (refcount_read(&cell->ref) > 0 && cell->net->live) |
| | 650 | queue_work(afs_wq, &cell->manager); |
| | 651 | } |
| | 652 | |
| | 653 | /* |
| | 654 | * Set/reduce the cell timer. |
| | 655 | */ |
| | 656 | void afs_set_cell_timer(struct afs_cell *cell, unsigned int delay_secs) |
| | 657 | { |
| | 658 | timer_reduce(&cell->management_timer, jiffies + delay_secs * HZ); |
| 658 | } | 659 | } |
| 659 | | 660 | |
| 660 | /* | 661 | /* |
| @@ -737,212 +738,125 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell) · 76 unmodified lines |
| 737 | _leave(""); | 738 | _leave(""); |
| 738 | } | 739 | } |
| 739 | | 740 | |
| | 741 | static bool afs_has_cell_expired(struct afs_cell *cell, time64_t *_next_manage) |
| | 742 | { |
| | 743 | const struct afs_vlserver_list *vllist; |
| | 744 | time64_t expire_at = cell->last_inactive; |
| | 745 | time64_t now = ktime_get_real_seconds(); |
| | 746 | |
| | 747 | if (atomic_read(&cell->active)) |
| | 748 | return false; |
| | 749 | if (!cell->net->live) |
| | 750 | return true; |
| | 751 | |
| | 752 | vllist = rcu_dereference_protected(cell->vl_servers, true); |
| | 753 | if (vllist && vllist->nr_servers > 0) |
| | 754 | expire_at += afs_cell_gc_delay; |
| | 755 | |
| | 756 | if (expire_at <= now) |
| | 757 | return true; |
| | 758 | if (expire_at < *_next_manage) |
| | 759 | *_next_manage = expire_at; |
| | 760 | return false; |
| | 761 | } |
| | 762 | |
| 740 | /* | 763 | /* |
| 741 | * Manage a cell record, initialising and destroying it, maintaining its DNS | 764 | * Manage a cell record, initialising and destroying it, maintaining its DNS |
| 742 | * records. | 765 | * records. |
| 743 | */ | 766 | */ |
| 744 | static void afs_manage_cell(struct afs_cell *cell) | 767 | static bool afs_manage_cell(struct afs_cell *cell) |
| 745 | { | 768 | { |
| 746 | struct afs_net *net = cell->net; | 769 | struct afs_net *net = cell->net; |
| 747 | int ret, active; | 770 | time64_t next_manage = TIME64_MAX; |
| | 771 | int ret; |
| 748 | | 772 | |
| 749 | _enter("%s", cell->name); | 773 | _enter("%s", cell->name); |
| 750 | | 774 | |
| 751 | again: | | |
| 752 | _debug("state %u", cell->state); | 775 | _debug("state %u", cell->state); |
| 753 | switch (cell->state) { | 776 | switch (cell->state) { |
| 754 | case AFS_CELL_INACTIVE: | 777 | case AFS_CELL_SETTING_UP: |
| 755 | case AFS_CELL_FAILED: | 778 | goto set_up_cell; |
| 756 | down_write(&net->cells_lock); | 779 | case AFS_CELL_ACTIVE: |
| 757 | active = 1; | 780 | goto cell_is_active; |
| 758 | if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) { | 781 | case AFS_CELL_REMOVING: |
| 759 | rb_erase(&cell->net_node, &net->cells); | 782 | WARN_ON_ONCE(1); |
| 760 | trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), 0, | 783 | return false; |
| 761 | afs_cell_trace_unuse_delete); | 784 | case AFS_CELL_DEAD: |
| 762 | smp_store_release(&cell->state, AFS_CELL_REMOVED); | 785 | return false; |
| 763 | } | 786 | default: |
| 764 | up_write(&net->cells_lock); | 787 | _debug("bad state %u", cell->state); |
| 765 | if (cell->state == AFS_CELL_REMOVED) { | 788 | WARN_ON_ONCE(1); /* Unhandled state */ |
| 766 | wake_up_var(&cell->state); | 789 | return false; |
| 767 | goto final_destruction; | 790 | } |
| 768 | } | | |
| 769 | if (cell->state == AFS_CELL_FAILED) | | |
| 770 | goto done; | | |
| 771 | smp_store_release(&cell->state, AFS_CELL_UNSET); | | |
| 772 | wake_up_var(&cell->state); | | |
| 773 | goto again; | | |
| 774 | | | |
| 775 | case AFS_CELL_UNSET: | | |
| 776 | smp_store_release(&cell->state, AFS_CELL_ACTIVATING); | | |
| 777 | wake_up_var(&cell->state); | | |
| 778 | goto again; | | |
| 779 | | | |
| 780 | case AFS_CELL_ACTIVATING: | | |
| 781 | ret = afs_activate_cell(net, cell); | | |
| 782 | if (ret < 0) | | |
| 783 | goto activation_failed; | | |
| 784 | | 791 | |
| 785 | smp_store_release(&cell->state, AFS_CELL_ACTIVE); | 792 | set_up_cell: |
| 786 | wake_up_var(&cell->state); | 793 | ret = afs_activate_cell(net, cell); |
| 787 | goto again; | 794 | if (ret < 0) { |
| | 795 | cell->error = ret; |
| | 796 | goto remove_cell; |
| | 797 | } |
| 788 | | 798 | |
| 789 | case AFS_CELL_ACTIVE: | 799 | afs_set_cell_state(cell, AFS_CELL_ACTIVE); |
| 790 | if (atomic_read(&cell->active) > 1) { | | |
| 791 | if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) { | | |
| 792 | ret = afs_update_cell(cell); | | |
| 793 | if (ret < 0) | | |
| 794 | cell->error = ret; | | |
| 795 | } | | |
| 796 | goto done; | | |
| 797 | } | | |
| 798 | smp_store_release(&cell->state, AFS_CELL_DEACTIVATING); | | |
| 799 | wake_up_var(&cell->state); | | |
| 800 | goto again; | | |
| 801 | | 800 | |
| 802 | case AFS_CELL_DEACTIVATING: | 801 | cell_is_active: |
| 803 | if (atomic_read(&cell->active) > 1) | 802 | if (afs_has_cell_expired(cell, &next_manage)) |
| 804 | goto reverse_deactivation; | 803 | goto remove_cell; |
| 805 | afs_deactivate_cell(net, cell); | | |
| 806 | smp_store_release(&cell->state, AFS_CELL_INACTIVE); | | |
| 807 | wake_up_var(&cell->state); | | |
| 808 | goto again; | | |
| 809 | | 804 | |
| 810 | case AFS_CELL_REMOVED: | 805 | if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) { |
| 811 | goto done; | 806 | ret = afs_update_cell(cell); |
| | 807 | if (ret < 0) |
| | 808 | cell->error = ret; |
| | 809 | } |
| 812 | | 810 | |
| 813 | default: | 811 | if (next_manage < TIME64_MAX && cell->net->live) { |
| 814 | break; | 812 | time64_t now = ktime_get_real_seconds(); |
| | 813 | |
| | 814 | if (next_manage - now <= 0) |
| | 815 | afs_queue_cell(cell, afs_cell_trace_queue_again); |
| | 816 | else |
| | 817 | afs_set_cell_timer(cell, next_manage - now); |
| 815 | } | 818 | } |
| 816 | _debug("bad state %u", cell->state); | 819 | _leave(" [done %u]", cell->state); |
| 817 | BUG(); /* Unhandled state */ | 820 | return false; |
| 818 | | 821 | |
| 819 | activation_failed: | 822 | remove_cell: |
| 820 | cell->error = ret; | 823 | down_write(&net->cells_lock); |
| 821 | afs_deactivate_cell(net, cell); | | |
| 822 | | 824 | |
| 823 | smp_store_release(&cell->state, AFS_CELL_FAILED); /* vs error */ | 825 | if (atomic_read(&cell->active)) { |
| 824 | wake_up_var(&cell->state); | 826 | up_write(&net->cells_lock); |
| 825 | goto again; | 827 | goto cell_is_active; |
| | 828 | } |
| 826 | | 829 | |
| 827 | reverse_deactivation: | 830 | /* Make sure that the expiring server records are going to see the fact |
| 828 | smp_store_release(&cell->state, AFS_CELL_ACTIVE); | 831 | * that the cell is caput. |
| 829 | wake_up_var(&cell->state); | 832 | */ |
| 830 | _leave(" [deact->act]"); | 833 | afs_set_cell_state(cell, AFS_CELL_REMOVING); |
| 831 | return; | | |
| 832 | | 834 | |
| 833 | done: | 835 | afs_deactivate_cell(net, cell); |
| 834 | _leave(" [done %u]", cell->state); | 836 | afs_purge_servers(cell); |
| 835 | return; | 837 | |
| | 838 | rb_erase(&cell->net_node, &net->cells); |
| | 839 | afs_see_cell(cell, afs_cell_trace_unuse_delete); |
| | 840 | up_write(&net->cells_lock); |
| 836 | | 841 | |
| 837 | final_destruction: | | |
| 838 | /* The root volume is pinning the cell */ | 842 | /* The root volume is pinning the cell */ |
| 839 | afs_put_volume(cell->root_volume, afs_volume_trace_put_cell_root); | 843 | afs_put_volume(cell->root_volume, afs_volume_trace_put_cell_root); |
| 840 | cell->root_volume = NULL; | 844 | cell->root_volume = NULL; |
| 841 | afs_purge_servers(cell); | 845 | |
| 842 | afs_put_cell(cell, afs_cell_trace_put_destroy); | 846 | afs_set_cell_state(cell, AFS_CELL_DEAD); |
| | 847 | return true; |
| 843 | } | 848 | } |
| 844 | | 849 | |
| 845 | static void afs_manage_cell_work(struct work_struct *work) | 850 | static void afs_manage_cell_work(struct work_struct *work) |
| 846 | { | 851 | { |
| 847 | struct afs_cell *cell = container_of(work, struct afs_cell, manager); | 852 | struct afs_cell *cell = container_of(work, struct afs_cell, manager); |
| | 853 | bool final_put; |
| 848 | | 854 | |
| 849 | afs_manage_cell(cell); | 855 | afs_see_cell(cell, afs_cell_trace_manage); |
| 850 | afs_put_cell(cell, afs_cell_trace_put_queue_work); | 856 | final_put = afs_manage_cell(cell); |
| 851 | } | 857 | afs_see_cell(cell, afs_cell_trace_managed); |
| 852 | | 858 | if (final_put) |
| 853 | /* | 859 | afs_put_cell(cell, afs_cell_trace_put_final); |
| 854 | * Manage the records of cells known to a network namespace. This includes | | |
| 855 | * updating the DNS records and garbage collecting unused cells that were | | |
| 856 | * automatically added. | | |
| 857 | * | | |
| 858 | * Note that constructed cell records may only be removed from net->cells by | | |
| 859 | * this work item, so it is safe for this work item to stash a cursor pointing | | |
| 860 | * into the tree and then return to caller (provided it skips cells that are | | |
| 861 | * still under construction). | | |
| 862 | * | | |
| 863 | * Note also that we were given an increment on net->cells_outstanding by | | |
| 864 | * whoever queued us that we need to deal with before returning. | | |
| 865 | */ | | |
| 866 | void afs_manage_cells(struct work_struct *work) | | |
| 867 | { | | |
| 868 | struct afs_net *net = container_of(work, struct afs_net, cells_manager); | | |
| 869 | struct rb_node *cursor; | | |
| 870 | time64_t now = ktime_get_real_seconds(), next_manage = TIME64_MAX; | | |
| 871 | bool purging = !net->live; | | |
| 872 | | | |
| 873 | _enter(""); | | |
| 874 | | | |
| 875 | /* Trawl the cell database looking for cells that have expired from | | |
| 876 | * lack of use and cells whose DNS results have expired and dispatch | | |
| 877 | * their managers. | | |
| 878 | */ | | |
| 879 | down_read(&net->cells_lock); | | |
| 880 | | | |
| 881 | for (cursor = rb_first(&net->cells); cursor; cursor = rb_next(cursor)) { | | |
| 882 | struct afs_cell *cell = | | |
| 883 | rb_entry(cursor, struct afs_cell, net_node); | | |
| 884 | unsigned active; | | |
| 885 | bool sched_cell = false; | | |
| 886 | | | |
| 887 | active = atomic_read(&cell->active); | | |
| 888 | trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), | | |
| 889 | active, afs_cell_trace_manage); | | |
| 890 | | | |
| 891 | ASSERTCMP(active, >=, 1); | | |
| 892 | | | |
| 893 | if (purging) { | | |
| 894 | if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) { | | |
| 895 | active = atomic_dec_return(&cell->active); | | |
| 896 | trace_afs_cell(cell->debug_id, refcount_read(&cell->ref), | | |
| 897 | active, afs_cell_trace_unuse_pin); | | |
| 898 | } | | |
| 899 | } | | |
| 900 | | | |
| 901 | if (active == 1) { | | |
| 902 | struct afs_vlserver_list *vllist; | | |
| 903 | time64_t expire_at = cell->last_inactive; | | |
| 904 | | | |
| 905 | read_lock(&cell->vl_servers_lock); | | |
| 906 | vllist = rcu_dereference_protected( | | |
| 907 | cell->vl_servers, | | |
| 908 | lockdep_is_held(&cell->vl_servers_lock)); | | |
| 909 | if (vllist->nr_servers > 0) | | |
| 910 | expire_at += afs_cell_gc_delay; | | |
| 911 | read_unlock(&cell->vl_servers_lock); | | |
| 912 | if (purging || expire_at <= now) | | |
| 913 | sched_cell = true; | | |
| 914 | else if (expire_at < next_manage) | | |
| 915 | next_manage = expire_at; | | |
| 916 | } | | |
| 917 | | | |
| 918 | if (!purging) { | | |
| 919 | if (test_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) | | |
| 920 | sched_cell = true; | | |
| 921 | } | | |
| 922 | | | |
| 923 | if (sched_cell) | | |
| 924 | afs_queue_cell(cell, afs_cell_trace_get_queue_manage); | | |
| 925 | } | | |
| 926 | | | |
| 927 | up_read(&net->cells_lock); | | |
| 928 | | | |
| 929 | /* Update the timer on the way out. We have to pass an increment on | | |
| 930 | * cells_outstanding in the namespace that we are in to the timer or | | |
| 931 | * the work scheduler. | | |
| 932 | */ | | |
| 933 | if (!purging && next_manage < TIME64_MAX) { | | |
| 934 | now = ktime_get_real_seconds(); | | |
| 935 | | | |
| 936 | if (next_manage - now <= 0) { | | |
| 937 | if (queue_work(afs_wq, &net->cells_manager)) | | |
| 938 | atomic_inc(&net->cells_outstanding); | | |
| 939 | } else { | | |
| 940 | afs_set_cell_timer(net, next_manage - now); | | |
| 941 | } | | |
| 942 | } | | |
| 943 | | | |
| 944 | afs_dec_cells_outstanding(net); | | |
| 945 | _leave(" [%d]", atomic_read(&net->cells_outstanding)); | | |
| 946 | } | 860 | } |
| 947 | | 861 | |
| 948 | /* | 862 | /* |
| @@ -951,6 +865,7 @@ void afs_manage_cells(struct work_struct *work) · 2 unmodified lines |
| 951 | void afs_cell_purge(struct afs_net *net) | 865 | void afs_cell_purge(struct afs_net *net) |
| 952 | { | 866 | { |
| 953 | struct afs_cell *ws; | 867 | struct afs_cell *ws; |
| | 868 | struct rb_node *cursor; |
| 954 | | 869 | |
| 955 | _enter(""); | 870 | _enter(""); |
| 956 | | 871 | |
| @@ -960,12 +875,19 @@ void afs_cell_purge(struct afs_net *net) · 3 unmodified lines |
| 960 | up_write(&net->cells_lock); | 875 | up_write(&net->cells_lock); |
| 961 | afs_unuse_cell(ws, afs_cell_trace_unuse_ws); | 876 | afs_unuse_cell(ws, afs_cell_trace_unuse_ws); |
| 962 | | 877 | |
| 963 | _debug("del timer"); | 878 | _debug("kick cells"); |
| 964 | if (del_timer_sync(&net->cells_timer)) | 879 | down_read(&net->cells_lock); |
| 965 | atomic_dec(&net->cells_outstanding); | 880 | for (cursor = rb_first(&net->cells); cursor; cursor = rb_next(cursor)) { |
| | 881 | struct afs_cell *cell = rb_entry(cursor, struct afs_cell, net_node); |
| | 882 | |
| | 883 | afs_see_cell(cell, afs_cell_trace_purge); |
| 966 | | 884 | |
| 967 | _debug("kick mgr"); | 885 | if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) |
| 968 | afs_queue_cell_manager(net); | 886 | afs_unuse_cell(cell, afs_cell_trace_unuse_pin); |
| | 887 | |
| | 888 | afs_queue_cell(cell, afs_cell_trace_queue_purge); |
| | 889 | } |
| | 890 | up_read(&net->cells_lock); |
| 969 | | 891 | |
| 970 | _debug("wait"); | 892 | _debug("wait"); |
| 971 | wait_var_event(&net->cells_outstanding, | 893 | wait_var_event(&net->cells_outstanding, |