Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'afs-fixes-20201016' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull afs updates from David Howells:
"A collection of fixes to fix afs_cell struct refcounting, thereby
fixing a slew of related syzbot bugs:

- Fix the cell tree in the netns to use an rwsem rather than RCU.

There seem to be some problems deriving from the use of RCU and a
seqlock to walk the rbtree, but it's not entirely clear what since
there are several different failures being seen.

Changing things to use an rwsem instead makes it more robust. The
extra performance derived from using RCU isn't necessary in this
case since the only time we're looking up a cell is during mount or
when cells are being manually added.

- Fix the refcounting by splitting the usage counter into a memory
refcount and an active users counter. The usage counter was doing
double duty, keeping track of whether a cell is still in use and
keeping track of when it needs to be destroyed - but this makes the
clean up tricky. Separating these out simplifies the logic.

- Fix purging a cell that has an alias. A cell alias pins the cell
it's an alias of, but the alias is always later in the list. Trying
to purge in a single pass causes rmmod to hang in such a case.

- Fix cell removal. If a cell's manager is requeued whilst it's
removing itself, the manager will run again and re-remove itself,
causing problems in various places. Follow Hillf Danton's
suggestion to insert a more terminal state that causes the manager
to do nothing post-removal.

In additional to the above, two other changes:

- Add a tracepoint for the cell refcount and active users count. This
helped with debugging the above and may be useful again in future.

- Downgrade an assertion to a print when a still-active server is
seen during purging. This was happening as a consequence of
incomplete cell removal before the servers were cleaned up"

* tag 'afs-fixes-20201016' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
afs: Don't assert on unpurgeable server records
afs: Add tracing for cell refcount and active user count
afs: Fix cell removal
afs: Fix cell purging with aliases
afs: Fix cell refcounting by splitting the usage counter
afs: Fix rapid cell addition/removal by not using RCU on cells tree

+377 -171
+208 -118
fs/afs/cell.c
··· 18 18 static unsigned __read_mostly afs_cell_gc_delay = 10; 19 19 static unsigned __read_mostly afs_cell_min_ttl = 10 * 60; 20 20 static unsigned __read_mostly afs_cell_max_ttl = 24 * 60 * 60; 21 + static atomic_t cell_debug_id; 21 22 22 - static void afs_manage_cell(struct work_struct *); 23 + static void afs_queue_cell_manager(struct afs_net *); 24 + static void afs_manage_cell_work(struct work_struct *); 23 25 24 26 static void afs_dec_cells_outstanding(struct afs_net *net) 25 27 { ··· 39 37 atomic_inc(&net->cells_outstanding); 40 38 if (timer_reduce(&net->cells_timer, jiffies + delay * HZ)) 41 39 afs_dec_cells_outstanding(net); 40 + } else { 41 + afs_queue_cell_manager(net); 42 42 } 43 43 } 44 44 45 45 /* 46 - * Look up and get an activation reference on a cell record under RCU 47 - * conditions. The caller must hold the RCU read lock. 46 + * Look up and get an activation reference on a cell record. The caller must 47 + * hold net->cells_lock at least read-locked. 48 48 */ 49 - struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net, 50 - const char *name, unsigned int namesz) 49 + static struct afs_cell *afs_find_cell_locked(struct afs_net *net, 50 + const char *name, unsigned int namesz, 51 + enum afs_cell_trace reason) 51 52 { 52 53 struct afs_cell *cell = NULL; 53 54 struct rb_node *p; 54 - int n, seq = 0, ret = 0; 55 + int n; 55 56 56 57 _enter("%*.*s", namesz, namesz, name); 57 58 ··· 63 58 if (namesz > AFS_MAXCELLNAME) 64 59 return ERR_PTR(-ENAMETOOLONG); 65 60 66 - do { 67 - /* Unfortunately, rbtree walking doesn't give reliable results 68 - * under just the RCU read lock, so we have to check for 69 - * changes. 70 - */ 71 - if (cell) 72 - afs_put_cell(net, cell); 73 - cell = NULL; 74 - ret = -ENOENT; 61 + if (!name) { 62 + cell = net->ws_cell; 63 + if (!cell) 64 + return ERR_PTR(-EDESTADDRREQ); 65 + goto found; 66 + } 75 67 76 - read_seqbegin_or_lock(&net->cells_lock, &seq); 68 + p = net->cells.rb_node; 69 + while (p) { 70 + cell = rb_entry(p, struct afs_cell, net_node); 77 71 78 - if (!name) { 79 - cell = rcu_dereference_raw(net->ws_cell); 80 - if (cell) { 81 - afs_get_cell(cell); 82 - ret = 0; 83 - break; 84 - } 85 - ret = -EDESTADDRREQ; 86 - continue; 87 - } 72 + n = strncasecmp(cell->name, name, 73 + min_t(size_t, cell->name_len, namesz)); 74 + if (n == 0) 75 + n = cell->name_len - namesz; 76 + if (n < 0) 77 + p = p->rb_left; 78 + else if (n > 0) 79 + p = p->rb_right; 80 + else 81 + goto found; 82 + } 88 83 89 - p = rcu_dereference_raw(net->cells.rb_node); 90 - while (p) { 91 - cell = rb_entry(p, struct afs_cell, net_node); 84 + return ERR_PTR(-ENOENT); 92 85 93 - n = strncasecmp(cell->name, name, 94 - min_t(size_t, cell->name_len, namesz)); 95 - if (n == 0) 96 - n = cell->name_len - namesz; 97 - if (n < 0) { 98 - p = rcu_dereference_raw(p->rb_left); 99 - } else if (n > 0) { 100 - p = rcu_dereference_raw(p->rb_right); 101 - } else { 102 - if (atomic_inc_not_zero(&cell->usage)) { 103 - ret = 0; 104 - break; 105 - } 106 - /* We want to repeat the search, this time with 107 - * the lock properly locked. 108 - */ 109 - } 110 - cell = NULL; 111 - } 86 + found: 87 + return afs_use_cell(cell, reason); 88 + } 112 89 113 - } while (need_seqretry(&net->cells_lock, seq)); 90 + /* 91 + * Look up and get an activation reference on a cell record. 92 + */ 93 + struct afs_cell *afs_find_cell(struct afs_net *net, 94 + const char *name, unsigned int namesz, 95 + enum afs_cell_trace reason) 96 + { 97 + struct afs_cell *cell; 114 98 115 - done_seqretry(&net->cells_lock, seq); 116 - 117 - if (ret != 0 && cell) 118 - afs_put_cell(net, cell); 119 - 120 - return ret == 0 ? cell : ERR_PTR(ret); 99 + down_read(&net->cells_lock); 100 + cell = afs_find_cell_locked(net, name, namesz, reason); 101 + up_read(&net->cells_lock); 102 + return cell; 121 103 } 122 104 123 105 /* ··· 158 166 cell->name[i] = tolower(name[i]); 159 167 cell->name[i] = 0; 160 168 161 - atomic_set(&cell->usage, 2); 162 - INIT_WORK(&cell->manager, afs_manage_cell); 169 + atomic_set(&cell->ref, 1); 170 + atomic_set(&cell->active, 0); 171 + INIT_WORK(&cell->manager, afs_manage_cell_work); 163 172 cell->volumes = RB_ROOT; 164 173 INIT_HLIST_HEAD(&cell->proc_volumes); 165 174 seqlock_init(&cell->volume_lock); ··· 199 206 cell->dns_source = vllist->source; 200 207 cell->dns_status = vllist->status; 201 208 smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */ 209 + atomic_inc(&net->cells_outstanding); 210 + cell->debug_id = atomic_inc_return(&cell_debug_id); 211 + trace_afs_cell(cell->debug_id, 1, 0, afs_cell_trace_alloc); 202 212 203 213 _leave(" = %p", cell); 204 214 return cell; ··· 241 245 _enter("%s,%s", name, vllist); 242 246 243 247 if (!excl) { 244 - rcu_read_lock(); 245 - cell = afs_lookup_cell_rcu(net, name, namesz); 246 - rcu_read_unlock(); 248 + cell = afs_find_cell(net, name, namesz, afs_cell_trace_use_lookup); 247 249 if (!IS_ERR(cell)) 248 250 goto wait_for_cell; 249 251 } ··· 262 268 /* Find the insertion point and check to see if someone else added a 263 269 * cell whilst we were allocating. 264 270 */ 265 - write_seqlock(&net->cells_lock); 271 + down_write(&net->cells_lock); 266 272 267 273 pp = &net->cells.rb_node; 268 274 parent = NULL; ··· 284 290 285 291 cell = candidate; 286 292 candidate = NULL; 293 + atomic_set(&cell->active, 2); 294 + trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 2, afs_cell_trace_insert); 287 295 rb_link_node_rcu(&cell->net_node, parent, pp); 288 296 rb_insert_color(&cell->net_node, &net->cells); 289 - atomic_inc(&net->cells_outstanding); 290 - write_sequnlock(&net->cells_lock); 297 + up_write(&net->cells_lock); 291 298 292 - queue_work(afs_wq, &cell->manager); 299 + afs_queue_cell(cell, afs_cell_trace_get_queue_new); 293 300 294 301 wait_for_cell: 302 + trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), atomic_read(&cell->active), 303 + afs_cell_trace_wait); 295 304 _debug("wait_for_cell"); 296 305 wait_var_event(&cell->state, 297 306 ({ 298 307 state = smp_load_acquire(&cell->state); /* vs error */ 299 - state == AFS_CELL_ACTIVE || state == AFS_CELL_FAILED; 308 + state == AFS_CELL_ACTIVE || state == AFS_CELL_REMOVED; 300 309 })); 301 310 302 311 /* Check the state obtained from the wait check. */ 303 - if (state == AFS_CELL_FAILED) { 312 + if (state == AFS_CELL_REMOVED) { 304 313 ret = cell->error; 305 314 goto error; 306 315 } ··· 317 320 if (excl) { 318 321 ret = -EEXIST; 319 322 } else { 320 - afs_get_cell(cursor); 323 + afs_use_cell(cursor, afs_cell_trace_use_lookup); 321 324 ret = 0; 322 325 } 323 - write_sequnlock(&net->cells_lock); 324 - kfree(candidate); 326 + up_write(&net->cells_lock); 327 + if (candidate) 328 + afs_put_cell(candidate, afs_cell_trace_put_candidate); 325 329 if (ret == 0) 326 330 goto wait_for_cell; 327 331 goto error_noput; 328 332 error: 329 - afs_put_cell(net, cell); 333 + afs_unuse_cell(net, cell, afs_cell_trace_unuse_lookup); 330 334 error_noput: 331 335 _leave(" = %d [error]", ret); 332 336 return ERR_PTR(ret); ··· 372 374 } 373 375 374 376 if (!test_and_set_bit(AFS_CELL_FL_NO_GC, &new_root->flags)) 375 - afs_get_cell(new_root); 377 + afs_use_cell(new_root, afs_cell_trace_use_pin); 376 378 377 379 /* install the new cell */ 378 - write_seqlock(&net->cells_lock); 379 - old_root = rcu_access_pointer(net->ws_cell); 380 - rcu_assign_pointer(net->ws_cell, new_root); 381 - write_sequnlock(&net->cells_lock); 380 + down_write(&net->cells_lock); 381 + afs_see_cell(new_root, afs_cell_trace_see_ws); 382 + old_root = net->ws_cell; 383 + net->ws_cell = new_root; 384 + up_write(&net->cells_lock); 382 385 383 - afs_put_cell(net, old_root); 386 + afs_unuse_cell(net, old_root, afs_cell_trace_unuse_ws); 384 387 _leave(" = 0"); 385 388 return 0; 386 389 } ··· 487 488 static void afs_cell_destroy(struct rcu_head *rcu) 488 489 { 489 490 struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu); 491 + struct afs_net *net = cell->net; 492 + int u; 490 493 491 494 _enter("%p{%s}", cell, cell->name); 492 495 493 - ASSERTCMP(atomic_read(&cell->usage), ==, 0); 496 + u = atomic_read(&cell->ref); 497 + ASSERTCMP(u, ==, 0); 498 + trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), afs_cell_trace_free); 494 499 495 - afs_put_volume(cell->net, cell->root_volume, afs_volume_trace_put_cell_root); 496 - afs_put_vlserverlist(cell->net, rcu_access_pointer(cell->vl_servers)); 497 - afs_put_cell(cell->net, cell->alias_of); 500 + afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers)); 501 + afs_unuse_cell(net, cell->alias_of, afs_cell_trace_unuse_alias); 498 502 key_put(cell->anonymous_key); 499 503 kfree(cell->name); 500 504 kfree(cell); 501 505 506 + afs_dec_cells_outstanding(net); 502 507 _leave(" [destroyed]"); 503 508 } 504 509 ··· 535 532 /* 536 533 * Get a reference on a cell record. 537 534 */ 538 - struct afs_cell *afs_get_cell(struct afs_cell *cell) 535 + struct afs_cell *afs_get_cell(struct afs_cell *cell, enum afs_cell_trace reason) 539 536 { 540 - atomic_inc(&cell->usage); 537 + int u; 538 + 539 + if (atomic_read(&cell->ref) <= 0) 540 + BUG(); 541 + 542 + u = atomic_inc_return(&cell->ref); 543 + trace_afs_cell(cell->debug_id, u, atomic_read(&cell->active), reason); 541 544 return cell; 542 545 } 543 546 544 547 /* 545 548 * Drop a reference on a cell record. 546 549 */ 547 - void afs_put_cell(struct afs_net *net, struct afs_cell *cell) 550 + void afs_put_cell(struct afs_cell *cell, enum afs_cell_trace reason) 548 551 { 552 + if (cell) { 553 + unsigned int debug_id = cell->debug_id; 554 + unsigned int u, a; 555 + 556 + a = atomic_read(&cell->active); 557 + u = atomic_dec_return(&cell->ref); 558 + trace_afs_cell(debug_id, u, a, reason); 559 + if (u == 0) { 560 + a = atomic_read(&cell->active); 561 + WARN(a != 0, "Cell active count %u > 0\n", a); 562 + call_rcu(&cell->rcu, afs_cell_destroy); 563 + } 564 + } 565 + } 566 + 567 + /* 568 + * Note a cell becoming more active. 569 + */ 570 + struct afs_cell *afs_use_cell(struct afs_cell *cell, enum afs_cell_trace reason) 571 + { 572 + int u, a; 573 + 574 + if (atomic_read(&cell->ref) <= 0) 575 + BUG(); 576 + 577 + u = atomic_read(&cell->ref); 578 + a = atomic_inc_return(&cell->active); 579 + trace_afs_cell(cell->debug_id, u, a, reason); 580 + return cell; 581 + } 582 + 583 + /* 584 + * Record a cell becoming less active. When the active counter reaches 1, it 585 + * is scheduled for destruction, but may get reactivated. 586 + */ 587 + void afs_unuse_cell(struct afs_net *net, struct afs_cell *cell, enum afs_cell_trace reason) 588 + { 589 + unsigned int debug_id = cell->debug_id; 549 590 time64_t now, expire_delay; 591 + int u, a; 550 592 551 593 if (!cell) 552 594 return; ··· 604 556 if (cell->vl_servers->nr_servers) 605 557 expire_delay = afs_cell_gc_delay; 606 558 607 - if (atomic_dec_return(&cell->usage) > 1) 608 - return; 559 + u = atomic_read(&cell->ref); 560 + a = atomic_dec_return(&cell->active); 561 + trace_afs_cell(debug_id, u, a, reason); 562 + WARN_ON(a == 0); 563 + if (a == 1) 564 + /* 'cell' may now be garbage collected. */ 565 + afs_set_cell_timer(net, expire_delay); 566 + } 609 567 610 - /* 'cell' may now be garbage collected. */ 611 - afs_set_cell_timer(net, expire_delay); 568 + /* 569 + * Note that a cell has been seen. 570 + */ 571 + void afs_see_cell(struct afs_cell *cell, enum afs_cell_trace reason) 572 + { 573 + int u, a; 574 + 575 + u = atomic_read(&cell->ref); 576 + a = atomic_read(&cell->active); 577 + trace_afs_cell(cell->debug_id, u, a, reason); 578 + } 579 + 580 + /* 581 + * Queue a cell for management, giving the workqueue a ref to hold. 582 + */ 583 + void afs_queue_cell(struct afs_cell *cell, enum afs_cell_trace reason) 584 + { 585 + afs_get_cell(cell, reason); 586 + if (!queue_work(afs_wq, &cell->manager)) 587 + afs_put_cell(cell, afs_cell_trace_put_queue_fail); 612 588 } 613 589 614 590 /* ··· 732 660 * Manage a cell record, initialising and destroying it, maintaining its DNS 733 661 * records. 734 662 */ 735 - static void afs_manage_cell(struct work_struct *work) 663 + static void afs_manage_cell(struct afs_cell *cell) 736 664 { 737 - struct afs_cell *cell = container_of(work, struct afs_cell, manager); 738 665 struct afs_net *net = cell->net; 739 - bool deleted; 740 - int ret, usage; 666 + int ret, active; 741 667 742 668 _enter("%s", cell->name); 743 669 ··· 744 674 switch (cell->state) { 745 675 case AFS_CELL_INACTIVE: 746 676 case AFS_CELL_FAILED: 747 - write_seqlock(&net->cells_lock); 748 - usage = 1; 749 - deleted = atomic_try_cmpxchg_relaxed(&cell->usage, &usage, 0); 750 - if (deleted) 677 + down_write(&net->cells_lock); 678 + active = 1; 679 + if (atomic_try_cmpxchg_relaxed(&cell->active, &active, 0)) { 751 680 rb_erase(&cell->net_node, &net->cells); 752 - write_sequnlock(&net->cells_lock); 753 - if (deleted) 681 + trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 0, 682 + afs_cell_trace_unuse_delete); 683 + smp_store_release(&cell->state, AFS_CELL_REMOVED); 684 + } 685 + up_write(&net->cells_lock); 686 + if (cell->state == AFS_CELL_REMOVED) { 687 + wake_up_var(&cell->state); 754 688 goto final_destruction; 689 + } 755 690 if (cell->state == AFS_CELL_FAILED) 756 691 goto done; 757 692 smp_store_release(&cell->state, AFS_CELL_UNSET); ··· 778 703 goto again; 779 704 780 705 case AFS_CELL_ACTIVE: 781 - if (atomic_read(&cell->usage) > 1) { 706 + if (atomic_read(&cell->active) > 1) { 782 707 if (test_and_clear_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags)) { 783 708 ret = afs_update_cell(cell); 784 709 if (ret < 0) ··· 791 716 goto again; 792 717 793 718 case AFS_CELL_DEACTIVATING: 794 - if (atomic_read(&cell->usage) > 1) 719 + if (atomic_read(&cell->active) > 1) 795 720 goto reverse_deactivation; 796 721 afs_deactivate_cell(net, cell); 797 722 smp_store_release(&cell->state, AFS_CELL_INACTIVE); 798 723 wake_up_var(&cell->state); 799 724 goto again; 725 + 726 + case AFS_CELL_REMOVED: 727 + goto done; 800 728 801 729 default: 802 730 break; ··· 826 748 return; 827 749 828 750 final_destruction: 829 - call_rcu(&cell->rcu, afs_cell_destroy); 830 - afs_dec_cells_outstanding(net); 831 - _leave(" [destruct %d]", atomic_read(&net->cells_outstanding)); 751 + /* The root volume is pinning the cell */ 752 + afs_put_volume(cell->net, cell->root_volume, afs_volume_trace_put_cell_root); 753 + cell->root_volume = NULL; 754 + afs_put_cell(cell, afs_cell_trace_put_destroy); 755 + } 756 + 757 + static void afs_manage_cell_work(struct work_struct *work) 758 + { 759 + struct afs_cell *cell = container_of(work, struct afs_cell, manager); 760 + 761 + afs_manage_cell(cell); 762 + afs_put_cell(cell, afs_cell_trace_put_queue_work); 832 763 } 833 764 834 765 /* ··· 866 779 * lack of use and cells whose DNS results have expired and dispatch 867 780 * their managers. 868 781 */ 869 - read_seqlock_excl(&net->cells_lock); 782 + down_read(&net->cells_lock); 870 783 871 784 for (cursor = rb_first(&net->cells); cursor; cursor = rb_next(cursor)) { 872 785 struct afs_cell *cell = 873 786 rb_entry(cursor, struct afs_cell, net_node); 874 - unsigned usage; 787 + unsigned active; 875 788 bool sched_cell = false; 876 789 877 - usage = atomic_read(&cell->usage); 878 - _debug("manage %s %u", cell->name, usage); 790 + active = atomic_read(&cell->active); 791 + trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 792 + active, afs_cell_trace_manage); 879 793 880 - ASSERTCMP(usage, >=, 1); 794 + ASSERTCMP(active, >=, 1); 881 795 882 796 if (purging) { 883 - if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) 884 - usage = atomic_dec_return(&cell->usage); 885 - ASSERTCMP(usage, ==, 1); 797 + if (test_and_clear_bit(AFS_CELL_FL_NO_GC, &cell->flags)) { 798 + active = atomic_dec_return(&cell->active); 799 + trace_afs_cell(cell->debug_id, atomic_read(&cell->ref), 800 + active, afs_cell_trace_unuse_pin); 801 + } 886 802 } 887 803 888 - if (usage == 1) { 804 + if (active == 1) { 889 805 struct afs_vlserver_list *vllist; 890 806 time64_t expire_at = cell->last_inactive; 891 807 ··· 911 821 } 912 822 913 823 if (sched_cell) 914 - queue_work(afs_wq, &cell->manager); 824 + afs_queue_cell(cell, afs_cell_trace_get_queue_manage); 915 825 } 916 826 917 - read_sequnlock_excl(&net->cells_lock); 827 + up_read(&net->cells_lock); 918 828 919 829 /* Update the timer on the way out. We have to pass an increment on 920 830 * cells_outstanding in the namespace that we are in to the timer or ··· 944 854 945 855 _enter(""); 946 856 947 - write_seqlock(&net->cells_lock); 948 - ws = rcu_access_pointer(net->ws_cell); 949 - RCU_INIT_POINTER(net->ws_cell, NULL); 950 - write_sequnlock(&net->cells_lock); 951 - afs_put_cell(net, ws); 857 + down_write(&net->cells_lock); 858 + ws = net->ws_cell; 859 + net->ws_cell = NULL; 860 + up_write(&net->cells_lock); 861 + afs_unuse_cell(net, ws, afs_cell_trace_unuse_ws); 952 862 953 863 _debug("del timer"); 954 864 if (del_timer_sync(&net->cells_timer))
+9 -14
fs/afs/dynroot.c
··· 123 123 len--; 124 124 } 125 125 126 - cell = afs_lookup_cell_rcu(net, name, len); 126 + cell = afs_find_cell(net, name, len, afs_cell_trace_use_probe); 127 127 if (!IS_ERR(cell)) { 128 - afs_put_cell(net, cell); 128 + afs_unuse_cell(net, cell, afs_cell_trace_unuse_probe); 129 129 return 0; 130 130 } 131 131 ··· 179 179 struct afs_cell *cell; 180 180 struct afs_net *net = afs_d2net(dentry); 181 181 struct dentry *ret; 182 - unsigned int seq = 0; 183 182 char *name; 184 183 int len; 185 184 ··· 190 191 if (!name) 191 192 goto out_p; 192 193 193 - rcu_read_lock(); 194 - do { 195 - read_seqbegin_or_lock(&net->cells_lock, &seq); 196 - cell = rcu_dereference_raw(net->ws_cell); 197 - if (cell) { 198 - len = cell->name_len; 199 - memcpy(name, cell->name, len + 1); 200 - } 201 - } while (need_seqretry(&net->cells_lock, seq)); 202 - done_seqretry(&net->cells_lock, seq); 203 - rcu_read_unlock(); 194 + down_read(&net->cells_lock); 195 + cell = net->ws_cell; 196 + if (cell) { 197 + len = cell->name_len; 198 + memcpy(name, cell->name, len + 1); 199 + } 200 + up_read(&net->cells_lock); 204 201 205 202 ret = ERR_PTR(-ENOENT); 206 203 if (!cell)
+14 -6
fs/afs/internal.h
··· 263 263 264 264 /* Cell database */ 265 265 struct rb_root cells; 266 - struct afs_cell __rcu *ws_cell; 266 + struct afs_cell *ws_cell; 267 267 struct work_struct cells_manager; 268 268 struct timer_list cells_timer; 269 269 atomic_t cells_outstanding; 270 - seqlock_t cells_lock; 270 + struct rw_semaphore cells_lock; 271 271 struct mutex cells_alias_lock; 272 272 273 273 struct mutex proc_cells_lock; ··· 326 326 AFS_CELL_DEACTIVATING, 327 327 AFS_CELL_INACTIVE, 328 328 AFS_CELL_FAILED, 329 + AFS_CELL_REMOVED, 329 330 }; 330 331 331 332 /* ··· 364 363 #endif 365 364 time64_t dns_expiry; /* Time AFSDB/SRV record expires */ 366 365 time64_t last_inactive; /* Time of last drop of usage count */ 367 - atomic_t usage; 366 + atomic_t ref; /* Struct refcount */ 367 + atomic_t active; /* Active usage counter */ 368 368 unsigned long flags; 369 369 #define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */ 370 370 #define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */ ··· 375 373 enum dns_record_source dns_source:8; /* Latest source of data from lookup */ 376 374 enum dns_lookup_status dns_status:8; /* Latest status of data from lookup */ 377 375 unsigned int dns_lookup_count; /* Counter of DNS lookups */ 376 + unsigned int debug_id; 378 377 379 378 /* The volumes belonging to this cell */ 380 379 struct rb_root volumes; /* Tree of volumes on this server */ ··· 920 917 * cell.c 921 918 */ 922 919 extern int afs_cell_init(struct afs_net *, const char *); 923 - extern struct afs_cell *afs_lookup_cell_rcu(struct afs_net *, const char *, unsigned); 920 + extern struct afs_cell *afs_find_cell(struct afs_net *, const char *, unsigned, 921 + enum afs_cell_trace); 924 922 extern struct afs_cell *afs_lookup_cell(struct afs_net *, const char *, unsigned, 925 923 const char *, bool); 926 - extern struct afs_cell *afs_get_cell(struct afs_cell *); 927 - extern void afs_put_cell(struct afs_net *, struct afs_cell *); 924 + extern struct afs_cell *afs_use_cell(struct afs_cell *, enum afs_cell_trace); 925 + extern void afs_unuse_cell(struct afs_net *, struct afs_cell *, enum afs_cell_trace); 926 + extern struct afs_cell *afs_get_cell(struct afs_cell *, enum afs_cell_trace); 927 + extern void afs_see_cell(struct afs_cell *, enum afs_cell_trace); 928 + extern void afs_put_cell(struct afs_cell *, enum afs_cell_trace); 929 + extern void afs_queue_cell(struct afs_cell *, enum afs_cell_trace); 928 930 extern void afs_manage_cells(struct work_struct *); 929 931 extern void afs_cells_timer(struct timer_list *); 930 932 extern void __net_exit afs_cell_purge(struct afs_net *);
+1 -1
fs/afs/main.c
··· 78 78 mutex_init(&net->socket_mutex); 79 79 80 80 net->cells = RB_ROOT; 81 - seqlock_init(&net->cells_lock); 81 + init_rwsem(&net->cells_lock); 82 82 INIT_WORK(&net->cells_manager, afs_manage_cells); 83 83 timer_setup(&net->cells_timer, afs_cells_timer, 0); 84 84
+2 -2
fs/afs/mntpt.c
··· 88 88 ctx->force = true; 89 89 } 90 90 if (ctx->cell) { 91 - afs_put_cell(ctx->net, ctx->cell); 91 + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_mntpt); 92 92 ctx->cell = NULL; 93 93 } 94 94 if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { ··· 124 124 char *buf; 125 125 126 126 if (src_as->cell) 127 - ctx->cell = afs_get_cell(src_as->cell); 127 + ctx->cell = afs_use_cell(src_as->cell, afs_cell_trace_use_mntpt); 128 128 129 129 if (size < 2 || size > PAGE_SIZE - 1) 130 130 return -EINVAL;
+11 -12
fs/afs/proc.c
··· 38 38 39 39 if (v == SEQ_START_TOKEN) { 40 40 /* display header on line 1 */ 41 - seq_puts(m, "USE TTL SV ST NAME\n"); 41 + seq_puts(m, "USE ACT TTL SV ST NAME\n"); 42 42 return 0; 43 43 } 44 44 ··· 46 46 vllist = rcu_dereference(cell->vl_servers); 47 47 48 48 /* display one cell per line on subsequent lines */ 49 - seq_printf(m, "%3u %6lld %2u %2u %s\n", 50 - atomic_read(&cell->usage), 49 + seq_printf(m, "%3u %3u %6lld %2u %2u %s\n", 50 + atomic_read(&cell->ref), 51 + atomic_read(&cell->active), 51 52 cell->dns_expiry - ktime_get_real_seconds(), 52 - vllist->nr_servers, 53 + vllist ? vllist->nr_servers : 0, 53 54 cell->state, 54 55 cell->name); 55 56 return 0; ··· 129 128 } 130 129 131 130 if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags)) 132 - afs_put_cell(net, cell); 131 + afs_unuse_cell(net, cell, afs_cell_trace_unuse_no_pin); 133 132 } else { 134 133 goto inval; 135 134 } ··· 155 154 struct afs_net *net; 156 155 157 156 net = afs_seq2net_single(m); 158 - if (rcu_access_pointer(net->ws_cell)) { 159 - rcu_read_lock(); 160 - cell = rcu_dereference(net->ws_cell); 161 - if (cell) 162 - seq_printf(m, "%s\n", cell->name); 163 - rcu_read_unlock(); 164 - } 157 + down_read(&net->cells_lock); 158 + cell = net->ws_cell; 159 + if (cell) 160 + seq_printf(m, "%s\n", cell->name); 161 + up_read(&net->cells_lock); 165 162 return 0; 166 163 } 167 164
+6 -1
fs/afs/server.c
··· 550 550 551 551 _debug("manage %pU %u", &server->uuid, active); 552 552 553 - ASSERTIFCMP(purging, active, ==, 0); 553 + if (purging) { 554 + trace_afs_server(server, atomic_read(&server->ref), 555 + active, afs_server_trace_purging); 556 + if (active != 0) 557 + pr_notice("Can't purge s=%08x\n", server->debug_id); 558 + } 554 559 555 560 if (active == 0) { 556 561 time64_t expire_at = server->unuse_time;
+9 -9
fs/afs/super.c
··· 294 294 cellnamesz, cellnamesz, cellname ?: ""); 295 295 return PTR_ERR(cell); 296 296 } 297 - afs_put_cell(ctx->net, ctx->cell); 297 + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_parse); 298 + afs_see_cell(cell, afs_cell_trace_see_source); 298 299 ctx->cell = cell; 299 300 } 300 301 ··· 390 389 _debug("switch to alias"); 391 390 key_put(ctx->key); 392 391 ctx->key = NULL; 393 - cell = afs_get_cell(ctx->cell->alias_of); 394 - afs_put_cell(ctx->net, ctx->cell); 392 + cell = afs_use_cell(ctx->cell->alias_of, 393 + afs_cell_trace_use_fc_alias); 394 + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); 395 395 ctx->cell = cell; 396 396 goto reget_key; 397 397 } ··· 509 507 if (ctx->dyn_root) { 510 508 as->dyn_root = true; 511 509 } else { 512 - as->cell = afs_get_cell(ctx->cell); 510 + as->cell = afs_use_cell(ctx->cell, afs_cell_trace_use_sbi); 513 511 as->volume = afs_get_volume(ctx->volume, 514 512 afs_volume_trace_get_alloc_sbi); 515 513 } ··· 522 520 if (as) { 523 521 struct afs_net *net = afs_net(as->net_ns); 524 522 afs_put_volume(net, as->volume, afs_volume_trace_put_destroy_sbi); 525 - afs_put_cell(net, as->cell); 523 + afs_unuse_cell(net, as->cell, afs_cell_trace_unuse_sbi); 526 524 put_net(as->net_ns); 527 525 kfree(as); 528 526 } ··· 608 606 609 607 afs_destroy_sbi(fc->s_fs_info); 610 608 afs_put_volume(ctx->net, ctx->volume, afs_volume_trace_put_free_fc); 611 - afs_put_cell(ctx->net, ctx->cell); 609 + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); 612 610 key_put(ctx->key); 613 611 kfree(ctx); 614 612 } ··· 635 633 ctx->net = afs_net(fc->net_ns); 636 634 637 635 /* Default to the workstation cell. */ 638 - rcu_read_lock(); 639 - cell = afs_lookup_cell_rcu(ctx->net, NULL, 0); 640 - rcu_read_unlock(); 636 + cell = afs_find_cell(ctx->net, NULL, 0, afs_cell_trace_use_fc); 641 637 if (IS_ERR(cell)) 642 638 cell = NULL; 643 639 ctx->cell = cell;
+4 -4
fs/afs/vl_alias.c
··· 177 177 178 178 is_alias: 179 179 rcu_read_unlock(); 180 - cell->alias_of = afs_get_cell(p); 180 + cell->alias_of = afs_use_cell(p, afs_cell_trace_use_alias); 181 181 return 1; 182 182 } 183 183 ··· 247 247 continue; 248 248 if (p->root_volume) 249 249 continue; /* Ignore cells that have a root.cell volume. */ 250 - afs_get_cell(p); 250 + afs_use_cell(p, afs_cell_trace_use_check_alias); 251 251 mutex_unlock(&cell->net->proc_cells_lock); 252 252 253 253 if (afs_query_for_alias_one(cell, key, p) != 0) 254 254 goto is_alias; 255 255 256 256 if (mutex_lock_interruptible(&cell->net->proc_cells_lock) < 0) { 257 - afs_put_cell(cell->net, p); 257 + afs_unuse_cell(cell->net, p, afs_cell_trace_unuse_check_alias); 258 258 return -ERESTARTSYS; 259 259 } 260 260 261 - afs_put_cell(cell->net, p); 261 + afs_unuse_cell(cell->net, p, afs_cell_trace_unuse_check_alias); 262 262 } 263 263 264 264 mutex_unlock(&cell->net->proc_cells_lock);
+1 -1
fs/afs/vl_rotate.c
··· 45 45 cell->dns_expiry <= ktime_get_real_seconds()) { 46 46 dns_lookup_count = smp_load_acquire(&cell->dns_lookup_count); 47 47 set_bit(AFS_CELL_FL_DO_LOOKUP, &cell->flags); 48 - queue_work(afs_wq, &cell->manager); 48 + afs_queue_cell(cell, afs_cell_trace_get_queue_dns); 49 49 50 50 if (cell->dns_source == DNS_RECORD_UNAVAILABLE) { 51 51 if (wait_var_event_interruptible(
+3 -3
fs/afs/volume.c
··· 83 83 84 84 volume->vid = vldb->vid[params->type]; 85 85 volume->update_at = ktime_get_real_seconds() + afs_volume_record_life; 86 - volume->cell = afs_get_cell(params->cell); 86 + volume->cell = afs_get_cell(params->cell, afs_cell_trace_get_vol); 87 87 volume->type = params->type; 88 88 volume->type_force = params->force; 89 89 volume->name_len = vldb->name_len; ··· 106 106 return volume; 107 107 108 108 error_1: 109 - afs_put_cell(params->net, volume->cell); 109 + afs_put_cell(volume->cell, afs_cell_trace_put_vol); 110 110 kfree(volume); 111 111 error_0: 112 112 return ERR_PTR(ret); ··· 228 228 229 229 afs_remove_volume_from_cell(volume); 230 230 afs_put_serverlist(net, rcu_access_pointer(volume->servers)); 231 - afs_put_cell(net, volume->cell); 231 + afs_put_cell(volume->cell, afs_cell_trace_put_vol); 232 232 trace_afs_volume(volume->vid, atomic_read(&volume->usage), 233 233 afs_volume_trace_free); 234 234 kfree_rcu(volume, rcu);
+109
include/trace/events/afs.h
··· 40 40 afs_server_trace_get_new_cbi, 41 41 afs_server_trace_get_probe, 42 42 afs_server_trace_give_up_cb, 43 + afs_server_trace_purging, 43 44 afs_server_trace_put_call, 44 45 afs_server_trace_put_cbi, 45 46 afs_server_trace_put_find_rsq, ··· 50 49 afs_server_trace_put_uuid_rsq, 51 50 afs_server_trace_update, 52 51 }; 52 + 53 53 54 54 enum afs_volume_trace { 55 55 afs_volume_trace_alloc, ··· 67 65 afs_volume_trace_put_query_alias, 68 66 afs_volume_trace_put_validate_fc, 69 67 afs_volume_trace_remove, 68 + }; 69 + 70 + enum afs_cell_trace { 71 + afs_cell_trace_alloc, 72 + afs_cell_trace_free, 73 + afs_cell_trace_get_queue_dns, 74 + afs_cell_trace_get_queue_manage, 75 + afs_cell_trace_get_queue_new, 76 + afs_cell_trace_get_vol, 77 + afs_cell_trace_insert, 78 + afs_cell_trace_manage, 79 + afs_cell_trace_put_candidate, 80 + afs_cell_trace_put_destroy, 81 + afs_cell_trace_put_queue_fail, 82 + afs_cell_trace_put_queue_work, 83 + afs_cell_trace_put_vol, 84 + afs_cell_trace_see_source, 85 + afs_cell_trace_see_ws, 86 + afs_cell_trace_unuse_alias, 87 + afs_cell_trace_unuse_check_alias, 88 + afs_cell_trace_unuse_delete, 89 + afs_cell_trace_unuse_fc, 90 + afs_cell_trace_unuse_lookup, 91 + afs_cell_trace_unuse_mntpt, 92 + afs_cell_trace_unuse_no_pin, 93 + afs_cell_trace_unuse_parse, 94 + afs_cell_trace_unuse_pin, 95 + afs_cell_trace_unuse_probe, 96 + afs_cell_trace_unuse_sbi, 97 + afs_cell_trace_unuse_ws, 98 + afs_cell_trace_use_alias, 99 + afs_cell_trace_use_check_alias, 100 + afs_cell_trace_use_fc, 101 + afs_cell_trace_use_fc_alias, 102 + afs_cell_trace_use_lookup, 103 + afs_cell_trace_use_mntpt, 104 + afs_cell_trace_use_pin, 105 + afs_cell_trace_use_probe, 106 + afs_cell_trace_use_sbi, 107 + afs_cell_trace_wait, 70 108 }; 71 109 72 110 enum afs_fs_operation { ··· 312 270 EM(afs_server_trace_get_new_cbi, "GET cbi ") \ 313 271 EM(afs_server_trace_get_probe, "GET probe") \ 314 272 EM(afs_server_trace_give_up_cb, "giveup-cb") \ 273 + EM(afs_server_trace_purging, "PURGE ") \ 315 274 EM(afs_server_trace_put_call, "PUT call ") \ 316 275 EM(afs_server_trace_put_cbi, "PUT cbi ") \ 317 276 EM(afs_server_trace_put_find_rsq, "PUT f-rsq") \ ··· 337 294 EM(afs_volume_trace_put_query_alias, "PUT cell-alias") \ 338 295 EM(afs_volume_trace_put_validate_fc, "PUT fc-validat") \ 339 296 E_(afs_volume_trace_remove, "REMOVE ") 297 + 298 + #define afs_cell_traces \ 299 + EM(afs_cell_trace_alloc, "ALLOC ") \ 300 + EM(afs_cell_trace_free, "FREE ") \ 301 + EM(afs_cell_trace_get_queue_dns, "GET q-dns ") \ 302 + EM(afs_cell_trace_get_queue_manage, "GET q-mng ") \ 303 + EM(afs_cell_trace_get_queue_new, "GET q-new ") \ 304 + EM(afs_cell_trace_get_vol, "GET vol ") \ 305 + EM(afs_cell_trace_insert, "INSERT ") \ 306 + EM(afs_cell_trace_manage, "MANAGE ") \ 307 + EM(afs_cell_trace_put_candidate, "PUT candid") \ 308 + EM(afs_cell_trace_put_destroy, "PUT destry") \ 309 + EM(afs_cell_trace_put_queue_work, "PUT q-work") \ 310 + EM(afs_cell_trace_put_queue_fail, "PUT q-fail") \ 311 + EM(afs_cell_trace_put_vol, "PUT vol ") \ 312 + EM(afs_cell_trace_see_source, "SEE source") \ 313 + EM(afs_cell_trace_see_ws, "SEE ws ") \ 314 + EM(afs_cell_trace_unuse_alias, "UNU alias ") \ 315 + EM(afs_cell_trace_unuse_check_alias, "UNU chk-al") \ 316 + EM(afs_cell_trace_unuse_delete, "UNU delete") \ 317 + EM(afs_cell_trace_unuse_fc, "UNU fc ") \ 318 + EM(afs_cell_trace_unuse_lookup, "UNU lookup") \ 319 + EM(afs_cell_trace_unuse_mntpt, "UNU mntpt ") \ 320 + EM(afs_cell_trace_unuse_parse, "UNU parse ") \ 321 + EM(afs_cell_trace_unuse_pin, "UNU pin ") \ 322 + EM(afs_cell_trace_unuse_probe, "UNU probe ") \ 323 + EM(afs_cell_trace_unuse_sbi, "UNU sbi ") \ 324 + EM(afs_cell_trace_unuse_ws, "UNU ws ") \ 325 + EM(afs_cell_trace_use_alias, "USE alias ") \ 326 + EM(afs_cell_trace_use_check_alias, "USE chk-al") \ 327 + EM(afs_cell_trace_use_fc, "USE fc ") \ 328 + EM(afs_cell_trace_use_fc_alias, "USE fc-al ") \ 329 + EM(afs_cell_trace_use_lookup, "USE lookup") \ 330 + EM(afs_cell_trace_use_mntpt, "USE mntpt ") \ 331 + EM(afs_cell_trace_use_pin, "USE pin ") \ 332 + EM(afs_cell_trace_use_probe, "USE probe ") \ 333 + EM(afs_cell_trace_use_sbi, "USE sbi ") \ 334 + E_(afs_cell_trace_wait, "WAIT ") 340 335 341 336 #define afs_fs_operations \ 342 337 EM(afs_FS_FetchData, "FS.FetchData") \ ··· 564 483 565 484 afs_call_traces; 566 485 afs_server_traces; 486 + afs_cell_traces; 567 487 afs_fs_operations; 568 488 afs_vl_operations; 569 489 afs_edit_dir_ops; ··· 1438 1356 __entry->vid, 1439 1357 __print_symbolic(__entry->reason, afs_volume_traces), 1440 1358 __entry->ref) 1359 + ); 1360 + 1361 + TRACE_EVENT(afs_cell, 1362 + TP_PROTO(unsigned int cell_debug_id, int usage, int active, 1363 + enum afs_cell_trace reason), 1364 + 1365 + TP_ARGS(cell_debug_id, usage, active, reason), 1366 + 1367 + TP_STRUCT__entry( 1368 + __field(unsigned int, cell ) 1369 + __field(int, usage ) 1370 + __field(int, active ) 1371 + __field(int, reason ) 1372 + ), 1373 + 1374 + TP_fast_assign( 1375 + __entry->cell = cell_debug_id; 1376 + __entry->usage = usage; 1377 + __entry->active = active; 1378 + __entry->reason = reason; 1379 + ), 1380 + 1381 + TP_printk("L=%08x %s u=%d a=%d", 1382 + __entry->cell, 1383 + __print_symbolic(__entry->reason, afs_cell_traces), 1384 + __entry->usage, 1385 + __entry->active) 1441 1386 ); 1442 1387 1443 1388 #endif /* _TRACE_AFS_H */