History

afs: Simplify cell record handling

Simplify afs_cell record handling to avoid very occasional races that cause module removal to hang (it waits for all cell records to be removed). There are two things that particularly contribute to the difficulty: firstly, the code tries to pass a ref on the cell to the cell's maintenance work item (which gets awkward if the work item is already queued); and, secondly, there's an overall cell manager that tries to use just one timer for the entire cell collection (to avoid having loads of timers). However, both of these are probably unnecessarily restrictive. To simplify this, the following changes are made: (1) The cell record collection manager is removed. Each cell record manages itself individually. (2) Each afs_cell is given a second work item (cell->destroyer) that is queued when its refcount reaches zero. This is not done in the context of the putting thread as it might be in an inconvenient place to sleep. (3) Each afs_cell is given its own timer. The timer is used to expire the cell record after a period of unuse if not otherwise pinned and can also be used for other maintenance tasks if necessary (of which there are currently none as DNS refresh is triggered by filesystem operations). (4) The afs_cell manager work item (cell->manager) is no longer given a ref on the cell when queued; rather, the manager must be deleted. This does away with the need to deal with the consequences of losing a race to queue cell->manager. Clean up of extra queuing is deferred to the destroyer. (5) The cell destroyer work item makes sure the cell timer is removed and that the normal cell work is cancelled before farming the actual destruction off to RCU. (6) When a network namespace is destroyed or the kafs module is unloaded, it's now a simple matter of marking the namespace as dead then just waking up all the cell work items. They will then remove and destroy themselves once all remaining activity counts and/or a ref counts are dropped. This makes sure that all server records are dropped first. (7) The cell record state set is reduced to just four states: SETTING_UP, ACTIVE, REMOVING and DEAD. The record persists in the active state even when it's not being used until the time comes to remove it rather than downgrading it to an inactive state from whence it can be restored. This means that the cell still appears in /proc and /afs when not in use until it switches to the REMOVING state - at which point it is removed. Note that the REMOVING state is included so that someone wanting to resurrect the cell record is forced to wait whilst the cell is torn down in that state. Once it's in the DEAD state, it has been removed from net->cells tree and is no longer findable and can be replaced.

David Howells committed 1 year ago

Commit e2c2cb81 parent 4882ba77 files · +187 −273Browse files

Unified · Split

7 files
  1. fs/afs/cell.c +163 −241
  2. fs/afs/dynroot.c +2 −2
  3. fs/afs/internal.h +6 −10
  4. fs/afs/main.c +0 −3
  5. fs/afs/server.c +4 −4
  6. fs/afs/vl_rotate.c +1 −1
  7. include/trace/events/afs.h +11 −12
fs/afs/cell.c+163−241
@@ -20,8 +20,9 @@ static unsigned __read_mostly afs_cell_min_ttl = 10 * 60; · 19 unmodified lines
20static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60;20static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60;
21static atomic_t cell_debug_id;21static atomic_t cell_debug_id;
22 22
23static void afs_queue_cell_manager(struct afs_net *);23static void afs_cell_timer(struct timer_list *timer);
24static void afs_manage_cell_work(struct work_struct *);24static void afs_destroy_cell_work(struct work_struct *work);
25static void afs_manage_cell_work(struct work_struct *work);
25 26
26static void afs_dec_cells_outstanding(struct afs_net *net)27static 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/*33static 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 */
36static 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");
222error:217error:
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
307wait_for_cell:302wait_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/*530static void afs_destroy_cell_work(struct work_struct *work)
534 * Queue the cell manager.
535 */
536static 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 */
550void 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 */
653void afs_queue_cell(struct afs_cell *cell, enum afs_cell_trace reason)636void 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 */
644static 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 */
656void 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
741static 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 DNS764 * Manage a cell record, initialising and destroying it, maintaining its DNS
742 * records.765 * records.
743 */766 */
744static void afs_manage_cell(struct afs_cell *cell)767static 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
751again:
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);792set_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:801cell_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
819activation_failed:822remove_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
827reverse_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
833done: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
837final_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
845static void afs_manage_cell_work(struct work_struct *work)850static 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 */
866void 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
951void afs_cell_purge(struct afs_net *net)865void 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,
fs/afs/dynroot.c+2−2
@@ -293,8 +293,8 @@ static int afs_dynroot_readdir_cells(struct afs_net *net, struct dir_context *ct · 292 unmodified lines
293 cell = idr_get_next(&net->cells_dyn_ino, &ix);293 cell = idr_get_next(&net->cells_dyn_ino, &ix);
294 if (!cell)294 if (!cell)
295 return 0;295 return 0;
296 if (READ_ONCE(cell->state) == AFS_CELL_FAILED ||296 if (READ_ONCE(cell->state) == AFS_CELL_REMOVING ||
297 READ_ONCE(cell->state) == AFS_CELL_REMOVED) {297 READ_ONCE(cell->state) == AFS_CELL_DEAD) {
298 ctx->pos += 2;298 ctx->pos += 2;
299 ctx->pos &= ~1;299 ctx->pos &= ~1;
300 continue;300 continue;
fs/afs/internal.h+6−10
@@ -289,8 +289,6 @@ struct afs_net { · 288 unmodified lines
289 struct rb_root cells;289 struct rb_root cells;
290 struct idr cells_dyn_ino; /* cell->dynroot_ino mapping */290 struct idr cells_dyn_ino; /* cell->dynroot_ino mapping */
291 struct afs_cell __rcu *ws_cell;291 struct afs_cell __rcu *ws_cell;
292 struct work_struct cells_manager;
293 struct timer_list cells_timer;
294 atomic_t cells_outstanding;292 atomic_t cells_outstanding;
295 struct rw_semaphore cells_lock;293 struct rw_semaphore cells_lock;
296 struct mutex cells_alias_lock;294 struct mutex cells_alias_lock;
@@ -339,13 +337,10 @@ struct afs_net { · 42 unmodified lines
339extern const char afs_init_sysname[];337extern const char afs_init_sysname[];
340 338
341enum afs_cell_state {339enum afs_cell_state {
342 AFS_CELL_UNSET,340 AFS_CELL_SETTING_UP,
343 AFS_CELL_ACTIVATING,
344 AFS_CELL_ACTIVE,341 AFS_CELL_ACTIVE,
345 AFS_CELL_DEACTIVATING,342 AFS_CELL_REMOVING,
346 AFS_CELL_INACTIVE,343 AFS_CELL_DEAD,
347 AFS_CELL_FAILED,
348 AFS_CELL_REMOVED,
349};344};
350 345
351/*346/*
@@ -376,7 +371,9 @@ struct afs_cell { · 24 unmodified lines
376 struct afs_cell *alias_of; /* The cell this is an alias of */371 struct afs_cell *alias_of; /* The cell this is an alias of */
377 struct afs_volume *root_volume; /* The root.cell volume if there is one */372 struct afs_volume *root_volume; /* The root.cell volume if there is one */
378 struct key *anonymous_key; /* anonymous user key for this cell */373 struct key *anonymous_key; /* anonymous user key for this cell */
374 struct work_struct destroyer; /* Destroyer for cell */
379 struct work_struct manager; /* Manager for init/deinit/dns */375 struct work_struct manager; /* Manager for init/deinit/dns */
376 struct timer_list management_timer; /* General management timer */
380 struct hlist_node proc_link; /* /proc cell list link */377 struct hlist_node proc_link; /* /proc cell list link */
381 time64_t dns_expiry; /* Time AFSDB/SRV record expires */378 time64_t dns_expiry; /* Time AFSDB/SRV record expires */
382 time64_t last_inactive; /* Time of last drop of usage count */379 time64_t last_inactive; /* Time of last drop of usage count */
@@ -1053,8 +1050,7 @@ extern struct afs_cell *afs_get_cell(struct afs_cell *, enum afs_cell_trace); · 670 unmodified lines
1053extern void afs_see_cell(struct afs_cell *, enum afs_cell_trace);1050extern void afs_see_cell(struct afs_cell *, enum afs_cell_trace);
1054extern void afs_put_cell(struct afs_cell *, enum afs_cell_trace);1051extern void afs_put_cell(struct afs_cell *, enum afs_cell_trace);
1055extern void afs_queue_cell(struct afs_cell *, enum afs_cell_trace);1052extern void afs_queue_cell(struct afs_cell *, enum afs_cell_trace);
1056extern void afs_manage_cells(struct work_struct *);1053void afs_set_cell_timer(struct afs_cell *cell, unsigned int delay_secs);
1057extern void afs_cells_timer(struct timer_list *);
1058extern void __net_exit afs_cell_purge(struct afs_net *);1054extern void __net_exit afs_cell_purge(struct afs_net *);
1059 1055
1060/*1056/*
fs/afs/main.c+0−3
@@ -78,9 +78,6 @@ static int __net_init afs_net_init(struct net *net_ns) · 77 unmodified lines
78 net->cells = RB_ROOT;78 net->cells = RB_ROOT;
79 idr_init(&net->cells_dyn_ino);79 idr_init(&net->cells_dyn_ino);
80 init_rwsem(&net->cells_lock);80 init_rwsem(&net->cells_lock);
81 INIT_WORK(&net->cells_manager, afs_manage_cells);
82 timer_setup(&net->cells_timer, afs_cells_timer, 0);
83
84 mutex_init(&net->cells_alias_lock);81 mutex_init(&net->cells_alias_lock);
85 mutex_init(&net->proc_cells_lock);82 mutex_init(&net->proc_cells_lock);
86 INIT_HLIST_HEAD(&net->proc_cells);83 INIT_HLIST_HEAD(&net->proc_cells);
fs/afs/server.c+4−4
@@ -103,7 +103,7 @@ static struct afs_server *afs_install_server(struct afs_cell *cell, · 102 unmodified lines
103 afs_get_cell(cell, afs_cell_trace_get_server);103 afs_get_cell(cell, afs_cell_trace_get_server);
104 104
105exists:105exists:
106 afs_use_server(server, true, afs_server_trace_get_install);106 afs_use_server(server, true, afs_server_trace_use_install);
107 return server;107 return server;
108}108}
109 109
@@ -356,7 +356,7 @@ void afs_unuse_server_notime(struct afs_net *net, struct afs_server *server, · 246 unmodified lines
356 356
357 if (atomic_dec_and_test(&server->active)) {357 if (atomic_dec_and_test(&server->active)) {
358 if (test_bit(AFS_SERVER_FL_EXPIRED, &server->flags) ||358 if (test_bit(AFS_SERVER_FL_EXPIRED, &server->flags) ||
359 READ_ONCE(server->cell->state) >= AFS_CELL_FAILED)359 READ_ONCE(server->cell->state) >= AFS_CELL_REMOVING)
360 schedule_work(&server->destroyer);360 schedule_work(&server->destroyer);
361 }361 }
362 362
@@ -374,7 +374,7 @@ void afs_unuse_server(struct afs_net *net, struct afs_server *server, · 11 unmodified lines
374 374
375 if (atomic_dec_and_test(&server->active)) {375 if (atomic_dec_and_test(&server->active)) {
376 if (!test_bit(AFS_SERVER_FL_EXPIRED, &server->flags) &&376 if (!test_bit(AFS_SERVER_FL_EXPIRED, &server->flags) &&
377 READ_ONCE(server->cell->state) < AFS_CELL_FAILED) {377 READ_ONCE(server->cell->state) < AFS_CELL_REMOVING) {
378 time64_t unuse_time = ktime_get_real_seconds();378 time64_t unuse_time = ktime_get_real_seconds();
379 379
380 server->unuse_time = unuse_time;380 server->unuse_time = unuse_time;
@@ -424,7 +424,7 @@ static bool afs_has_server_expired(const struct afs_server *server) · 43 unmodified lines
424 return false;424 return false;
425 425
426 if (server->cell->net->live ||426 if (server->cell->net->live ||
427 server->cell->state >= AFS_CELL_FAILED) {427 server->cell->state >= AFS_CELL_REMOVING) {
428 trace_afs_server(server->debug_id, refcount_read(&server->ref),428 trace_afs_server(server->debug_id, refcount_read(&server->ref),
429 0, afs_server_trace_purging);429 0, afs_server_trace_purging);
430 return true;430 return true;
fs/afs/vl_rotate.c+1−1
@@ -48,7 +48,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc) · 47 unmodified lines
48 cell->dns_expiry <= ktime_get_real_seconds()) {48 cell->dns_expiry <= ktime_get_real_seconds()) {
49 dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count);49 dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count);
50 set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags);50 set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags);
51 afs_queue_cell(cell, afs_cell_trace_get_queue_dns);51 afs_queue_cell(cell, afs_cell_trace_queue_dns);
52 52
53 if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {53 if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
54 if (wait_var_event_interruptible(54 if (wait_var_event_interruptible(
include/trace/events/afs.h+11−12
@@ -131,7 +131,6 @@ enum yfs_cm_operation { · 130 unmodified lines
131 EM(afs_server_trace_destroy, "DESTROY ") \131 EM(afs_server_trace_destroy, "DESTROY ") \
132 EM(afs_server_trace_free, "FREE ") \132 EM(afs_server_trace_free, "FREE ") \
133 EM(afs_server_trace_gc, "GC ") \133 EM(afs_server_trace_gc, "GC ") \
134 EM(afs_server_trace_get_install, "GET inst ") \
135 EM(afs_server_trace_get_probe, "GET probe") \134 EM(afs_server_trace_get_probe, "GET probe") \
136 EM(afs_server_trace_purging, "PURGE ") \135 EM(afs_server_trace_purging, "PURGE ") \
137 EM(afs_server_trace_put_cbi, "PUT cbi ") \136 EM(afs_server_trace_put_cbi, "PUT cbi ") \
@@ -149,6 +148,7 @@ enum yfs_cm_operation { · 11 unmodified lines
149 EM(afs_server_trace_use_cm_call, "USE cm-cl") \148 EM(afs_server_trace_use_cm_call, "USE cm-cl") \
150 EM(afs_server_trace_use_get_caps, "USE gcaps") \149 EM(afs_server_trace_use_get_caps, "USE gcaps") \
151 EM(afs_server_trace_use_give_up_cb, "USE gvupc") \150 EM(afs_server_trace_use_give_up_cb, "USE gvupc") \
151 EM(afs_server_trace_use_install, "USE inst ") \
152 E_(afs_server_trace_wait_create, "WAIT crt ")152 E_(afs_server_trace_wait_create, "WAIT crt ")
153 153
154#define afs_volume_traces \154#define afs_volume_traces \
@@ -171,37 +171,36 @@ enum yfs_cm_operation { · 16 unmodified lines
171 171
172#define afs_cell_traces \172#define afs_cell_traces \
173 EM(afs_cell_trace_alloc, "ALLOC ") \173 EM(afs_cell_trace_alloc, "ALLOC ") \
174 EM(afs_cell_trace_destroy, "DESTROY ") \
174 EM(afs_cell_trace_free, "FREE ") \175 EM(afs_cell_trace_free, "FREE ") \
175 EM(afs_cell_trace_get_atcell, "GET atcell") \176 EM(afs_cell_trace_get_atcell, "GET atcell") \
176 EM(afs_cell_trace_get_queue_dns, "GET q-dns ") \
177 EM(afs_cell_trace_get_queue_manage, "GET q-mng ") \
178 EM(afs_cell_trace_get_queue_new, "GET q-new ") \
179 EM(afs_cell_trace_get_server, "GET server") \177 EM(afs_cell_trace_get_server, "GET server") \
180 EM(afs_cell_trace_get_vol, "GET vol ") \178 EM(afs_cell_trace_get_vol, "GET vol ") \
181 EM(afs_cell_trace_insert, "INSERT ") \179 EM(afs_cell_trace_purge, "PURGE ") \
182 EM(afs_cell_trace_manage, "MANAGE ") \
183 EM(afs_cell_trace_put_atcell, "PUT atcell") \180 EM(afs_cell_trace_put_atcell, "PUT atcell") \
184 EM(afs_cell_trace_put_candidate, "PUT candid") \181 EM(afs_cell_trace_put_candidate, "PUT candid") \
185 EM(afs_cell_trace_put_destroy, "PUT destry") \182 EM(afs_cell_trace_put_final, "PUT final ") \
186 EM(afs_cell_trace_put_queue_work, "PUT q-work") \
187 EM(afs_cell_trace_put_queue_fail, "PUT q-fail") \
188 EM(afs_cell_trace_put_server, "PUT server") \183 EM(afs_cell_trace_put_server, "PUT server") \
189 EM(afs_cell_trace_put_vol, "PUT vol ") \184 EM(afs_cell_trace_put_vol, "PUT vol ") \
185 EM(afs_cell_trace_queue_again, "QUE again ") \
186 EM(afs_cell_trace_queue_dns, "QUE dns ") \
187 EM(afs_cell_trace_queue_new, "QUE new ") \
188 EM(afs_cell_trace_queue_purge, "QUE purge ") \
189 EM(afs_cell_trace_manage, "MANAGE ") \
190 EM(afs_cell_trace_managed, "MANAGED ") \
190 EM(afs_cell_trace_see_source, "SEE source") \191 EM(afs_cell_trace_see_source, "SEE source") \
191 EM(afs_cell_trace_see_ws, "SEE ws ") \192 EM(afs_cell_trace_see_mgmt_timer, "SEE mtimer") \
192 EM(afs_cell_trace_unuse_alias, "UNU alias ") \193 EM(afs_cell_trace_unuse_alias, "UNU alias ") \
193 EM(afs_cell_trace_unuse_check_alias, "UNU chk-al") \194 EM(afs_cell_trace_unuse_check_alias, "UNU chk-al") \
194 EM(afs_cell_trace_unuse_delete, "UNU delete") \195 EM(afs_cell_trace_unuse_delete, "UNU delete") \
195 EM(afs_cell_trace_unuse_dynroot_mntpt, "UNU dyn-mp") \196 EM(afs_cell_trace_unuse_dynroot_mntpt, "UNU dyn-mp") \
196 EM(afs_cell_trace_unuse_fc, "UNU fc ") \197 EM(afs_cell_trace_unuse_fc, "UNU fc ") \
197 EM(afs_cell_trace_unuse_lookup, "UNU lookup") \
198 EM(afs_cell_trace_unuse_lookup_dynroot, "UNU lu-dyn") \198 EM(afs_cell_trace_unuse_lookup_dynroot, "UNU lu-dyn") \
199 EM(afs_cell_trace_unuse_lookup_error, "UNU lu-err") \199 EM(afs_cell_trace_unuse_lookup_error, "UNU lu-err") \
200 EM(afs_cell_trace_unuse_mntpt, "UNU mntpt ") \200 EM(afs_cell_trace_unuse_mntpt, "UNU mntpt ") \
201 EM(afs_cell_trace_unuse_no_pin, "UNU no-pin") \201 EM(afs_cell_trace_unuse_no_pin, "UNU no-pin") \
202 EM(afs_cell_trace_unuse_parse, "UNU parse ") \202 EM(afs_cell_trace_unuse_parse, "UNU parse ") \
203 EM(afs_cell_trace_unuse_pin, "UNU pin ") \203 EM(afs_cell_trace_unuse_pin, "UNU pin ") \
204 EM(afs_cell_trace_unuse_probe, "UNU probe ") \
205 EM(afs_cell_trace_unuse_sbi, "UNU sbi ") \204 EM(afs_cell_trace_unuse_sbi, "UNU sbi ") \
206 EM(afs_cell_trace_unuse_ws, "UNU ws ") \205 EM(afs_cell_trace_unuse_ws, "UNU ws ") \
207 EM(afs_cell_trace_use_alias, "USE alias ") \206 EM(afs_cell_trace_use_alias, "USE alias ") \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t