wake_up_var(&net->servers_outstanding);
 }
 
+static struct afs_server *afs_maybe_use_server(struct afs_server *,
+                                              enum afs_server_trace);
+static void __afs_put_server(struct afs_net *, struct afs_server *);
+
 /*
  * Find a server by one of its addresses.
  */
 
        do {
                if (server)
-                       afs_put_server(net, server, afs_server_trace_put_find_rsq);
+                       afs_unuse_server_notime(net, server, afs_server_trace_put_find_rsq);
                server = NULL;
                read_seqbegin_or_lock(&net->fs_addr_lock, &seq);
 
                }
 
                server = NULL;
+               continue;
        found:
-               if (server && !atomic_inc_not_zero(&server->usage))
-                       server = NULL;
+               server = afs_maybe_use_server(server, afs_server_trace_get_by_addr);
 
        } while (need_seqretry(&net->fs_addr_lock, seq));
 
 }
 
 /*
- * Look up a server by its UUID
+ * Look up a server by its UUID and mark it active.
  */
 struct afs_server *afs_find_server_by_uuid(struct afs_net *net, const uuid_t *uuid)
 {
                 * changes.
                 */
                if (server)
-                       afs_put_server(net, server, afs_server_trace_put_uuid_rsq);
+                       afs_unuse_server(net, server, afs_server_trace_put_uuid_rsq);
                server = NULL;
 
                read_seqbegin_or_lock(&net->fs_lock, &seq);
                        } else if (diff > 0) {
                                p = p->rb_right;
                        } else {
-                               afs_get_server(server, afs_server_trace_get_by_uuid);
+                               afs_use_server(server, afs_server_trace_get_by_uuid);
                                break;
                        }
 
 }
 
 /*
- * allocate a new server record
+ * Allocate a new server record and mark it active.
  */
 static struct afs_server *afs_alloc_server(struct afs_net *net,
                                           const uuid_t *uuid,
        if (!server)
                goto enomem;
 
-       atomic_set(&server->usage, 1);
+       atomic_set(&server->ref, 1);
+       atomic_set(&server->active, 1);
        server->debug_id = atomic_inc_return(&afs_server_debug_id);
        RCU_INIT_POINTER(server->addresses, alist);
        server->addr_version = alist->version;
        spin_lock_init(&server->probe_lock);
 
        afs_inc_servers_outstanding(net);
-       trace_afs_server(server, 1, afs_server_trace_alloc);
+       trace_afs_server(server, 1, 1, afs_server_trace_alloc);
        _leave(" = %p", server);
        return server;
 
                kfree(candidate);
        }
 
-       _leave(" = %p{%d}", server, atomic_read(&server->usage));
        return server;
 }
 
 struct afs_server *afs_get_server(struct afs_server *server,
                                  enum afs_server_trace reason)
 {
-       unsigned int u = atomic_inc_return(&server->usage);
+       unsigned int u = atomic_inc_return(&server->ref);
+
+       trace_afs_server(server, u, atomic_read(&server->active), reason);
+       return server;
+}
+
+/*
+ * Try to get a reference on a server object.
+ */
+static struct afs_server *afs_maybe_use_server(struct afs_server *server,
+                                              enum afs_server_trace reason)
+{
+       unsigned int r = atomic_fetch_add_unless(&server->ref, 1, 0);
+       unsigned int a;
+
+       if (r == 0)
+               return NULL;
+
+       a = atomic_inc_return(&server->active);
+       trace_afs_server(server, r, a, reason);
+       return server;
+}
+
+/*
+ * Get an active count on a server object.
+ */
+struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_trace reason)
+{
+       unsigned int r = atomic_inc_return(&server->ref);
+       unsigned int a = atomic_inc_return(&server->active);
 
-       trace_afs_server(server, u, reason);
+       trace_afs_server(server, r, a, reason);
        return server;
 }
 
        if (!server)
                return;
 
-       server->put_time = ktime_get_real_seconds();
-
-       usage = atomic_dec_return(&server->usage);
+       usage = atomic_dec_return(&server->ref);
+       trace_afs_server(server, usage, atomic_read(&server->active), reason);
+       if (unlikely(usage == 0))
+               __afs_put_server(net, server);
+}
 
-       trace_afs_server(server, usage, reason);
+/*
+ * Drop an active count on a server object without updating the last-unused
+ * time.
+ */
+void afs_unuse_server_notime(struct afs_net *net, struct afs_server *server,
+                            enum afs_server_trace reason)
+{
+       if (server) {
+               unsigned int active = atomic_dec_return(&server->active);
 
-       if (likely(usage > 0))
-               return;
+               if (active == 0)
+                       afs_set_server_timer(net, afs_server_gc_delay);
+               afs_put_server(net, server, reason);
+       }
+}
 
-       afs_set_server_timer(net, afs_server_gc_delay);
+/*
+ * Drop an active count on a server object.
+ */
+void afs_unuse_server(struct afs_net *net, struct afs_server *server,
+                     enum afs_server_trace reason)
+{
+       if (server) {
+               server->unuse_time = ktime_get_real_seconds();
+               afs_unuse_server_notime(net, server, reason);
+       }
 }
 
 static void afs_server_rcu(struct rcu_head *rcu)
 {
        struct afs_server *server = container_of(rcu, struct afs_server, rcu);
 
-       trace_afs_server(server, atomic_read(&server->usage),
-                        afs_server_trace_free);
+       trace_afs_server(server, atomic_read(&server->ref),
+                        atomic_read(&server->active), afs_server_trace_free);
        afs_put_addrlist(rcu_access_pointer(server->addresses));
        kfree(server);
 }
 
+static void __afs_put_server(struct afs_net *net, struct afs_server *server)
+{
+       call_rcu(&server->rcu, afs_server_rcu);
+       afs_dec_servers_outstanding(net);
+}
+
 /*
  * destroy a dead server
  */
                .error  = 0,
        };
 
-       trace_afs_server(server, atomic_read(&server->usage),
-                        afs_server_trace_give_up_cb);
-
        if (test_bit(AFS_SERVER_FL_MAY_HAVE_CB, &server->flags))
                afs_fs_give_up_all_callbacks(net, server, &ac, NULL);
 
-       wait_var_event(&server->probe_outstanding,
-                      atomic_read(&server->probe_outstanding) == 0);
-
-       trace_afs_server(server, atomic_read(&server->usage),
-                        afs_server_trace_destroy);
-       call_rcu(&server->rcu, afs_server_rcu);
-       afs_dec_servers_outstanding(net);
+       afs_put_server(net, server, afs_server_trace_destroy);
 }
 
 /*
 static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list)
 {
        struct afs_server *server;
-       bool deleted;
-       int usage;
+       int active;
 
        while ((server = gc_list)) {
                gc_list = server->gc_next;
 
                write_seqlock(&net->fs_lock);
-               usage = 1;
-               deleted = atomic_try_cmpxchg(&server->usage, &usage, 0);
-               trace_afs_server(server, usage, afs_server_trace_gc);
-               if (deleted) {
+
+               active = atomic_read(&server->active);
+               if (active == 0) {
+                       trace_afs_server(server, atomic_read(&server->ref),
+                                        active, afs_server_trace_gc);
                        rb_erase(&server->uuid_rb, &net->fs_servers);
                        hlist_del_rcu(&server->proc_link);
-               }
-               write_sequnlock(&net->fs_lock);
-
-               if (deleted) {
-                       write_seqlock(&net->fs_addr_lock);
                        if (!hlist_unhashed(&server->addr4_link))
                                hlist_del_rcu(&server->addr4_link);
                        if (!hlist_unhashed(&server->addr6_link))
                                hlist_del_rcu(&server->addr6_link);
-                       write_sequnlock(&net->fs_addr_lock);
-                       afs_destroy_server(net, server);
                }
+               write_sequnlock(&net->fs_lock);
+
+               if (active == 0)
+                       afs_destroy_server(net, server);
        }
 }
 
        for (cursor = rb_first(&net->fs_servers); cursor; cursor = rb_next(cursor)) {
                struct afs_server *server =
                        rb_entry(cursor, struct afs_server, uuid_rb);
-               int usage = atomic_read(&server->usage);
+               int active = atomic_read(&server->active);
 
-               _debug("manage %pU %u", &server->uuid, usage);
+               _debug("manage %pU %u", &server->uuid, active);
 
-               ASSERTCMP(usage, >=, 1);
-               ASSERTIFCMP(purging, usage, ==, 1);
+               ASSERTIFCMP(purging, active, ==, 0);
 
-               if (usage == 1) {
-                       time64_t expire_at = server->put_time;
+               if (active == 0) {
+                       time64_t expire_at = server->unuse_time;
 
                        if (!test_bit(AFS_SERVER_FL_VL_FAIL, &server->flags) &&
                            !test_bit(AFS_SERVER_FL_NOT_FOUND, &server->flags))
 
        _enter("");
 
-       trace_afs_server(server, atomic_read(&server->usage), afs_server_trace_update);
+       trace_afs_server(server, atomic_read(&server->ref), atomic_read(&server->active),
+                        afs_server_trace_update);
 
        alist = afs_vl_lookup_addrs(fc->vnode->volume->cell, fc->key,
                                    &server->uuid);
 
        afs_server_trace_destroy,
        afs_server_trace_free,
        afs_server_trace_gc,
+       afs_server_trace_get_by_addr,
        afs_server_trace_get_by_uuid,
        afs_server_trace_get_caps,
        afs_server_trace_get_install,
        EM(afs_server_trace_destroy,            "DESTROY  ") \
        EM(afs_server_trace_free,               "FREE     ") \
        EM(afs_server_trace_gc,                 "GC       ") \
+       EM(afs_server_trace_get_by_addr,        "GET addr ") \
        EM(afs_server_trace_get_by_uuid,        "GET uuid ") \
        EM(afs_server_trace_get_caps,           "GET caps ") \
        EM(afs_server_trace_get_install,        "GET inst ") \
            );
 
 TRACE_EVENT(afs_server,
-           TP_PROTO(struct afs_server *server, int usage, enum afs_server_trace reason),
+           TP_PROTO(struct afs_server *server, int ref, int active,
+                    enum afs_server_trace reason),
 
-           TP_ARGS(server, usage, reason),
+           TP_ARGS(server, ref, active, reason),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               server          )
-                   __field(int,                        usage           )
+                   __field(int,                        ref             )
+                   __field(int,                        active          )
                    __field(int,                        reason          )
                             ),
 
            TP_fast_assign(
                    __entry->server = server->debug_id;
-                   __entry->usage = usage;
+                   __entry->ref = ref;
+                   __entry->active = active;
                    __entry->reason = reason;
                           ),
 
-           TP_printk("s=%08x %s u=%d",
+           TP_printk("s=%08x %s u=%d a=%d",
                      __entry->server,
                      __print_symbolic(__entry->reason, afs_server_traces),
-                     __entry->usage)
+                     __entry->ref,
+                     __entry->active)
            );
 
 #endif /* _TRACE_AFS_H */