selected:
        ac->index = index;
        set_bit(index, &ac->tried);
-       ac->responded = false;
+       ac->call_responded = false;
        return true;
 }
 
 /*
  * Release an address list cursor.
  */
-int afs_end_cursor(struct afs_addr_cursor *ac)
+void afs_end_cursor(struct afs_addr_cursor *ac)
 {
        struct afs_addr_list *alist;
 
        alist = ac->alist;
        if (alist) {
-               if (ac->responded &&
+               if (ac->call_responded &&
                    ac->index != alist->preferred &&
                    test_bit(ac->alist->preferred, &ac->tried))
                        WRITE_ONCE(alist->preferred, ac->index);
                afs_put_addrlist(alist);
                ac->alist = NULL;
        }
-
-       return ac->error;
 }
 
                        vp = &op->file[0];
                        abort_code = vp->scb.status.abort_code;
                        if (abort_code != 0) {
-                               op->ac.abort_code = abort_code;
-                               op->error = afs_abort_to_error(abort_code);
+                               op->call_abort_code = abort_code;
+                               afs_op_set_error(op, afs_abort_to_error(abort_code));
+                               op->cumul_error.abort_code = abort_code;
                        }
                        break;
 
        _debug("nr_files %u", op->nr_files);
 
        /* Need space for examining all the selected files */
-       op->error = -ENOMEM;
        if (op->nr_files > 2) {
                op->more_files = kvcalloc(op->nr_files - 2,
                                          sizeof(struct afs_vnode_param),
                                          GFP_KERNEL);
-               if (!op->more_files)
+               if (!op->more_files) {
+                       afs_op_nomem(op);
                        goto out_op;
+               }
 
                for (i = 2; i < op->nr_files; i++) {
                        vp = &op->more_files[i - 2];
 {
        struct afs_vnode *vnode = op->file[0].vnode;
 
-       switch (op->ac.abort_code) {
+       switch (afs_op_abort_code(op)) {
        case VNOVNODE:
                set_bit(AFS_VNODE_DELETED, &vnode->flags);
                afs_break_callback(vnode, afs_cb_break_for_deleted);
                /* ENOMEM or EINTR at a really inconvenient time - just abandon
                 * the new directory on the server.
                 */
-               op->error = PTR_ERR(inode);
+               afs_op_accumulate_error(op, PTR_ERR(inode), 0);
                return;
        }
 
 
        /* If there was a conflict with a third party, check the status of the
         * unlinked vnode.
         */
-       if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
+       if (op->cumul_error.error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
                op->file[1].update_ctime = false;
                op->fetch_status.which = 1;
                op->ops = &afs_fetch_status_operation;
 
        struct netfs_io_subrequest *subreq = req->subreq;
        int error = afs_op_error(op);
 
-       if (error == -ECONNABORTED)
-               error = afs_abort_to_error(op->ac.abort_code);
        req->error = error;
-
        if (subreq) {
                __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags);
                netfs_subreq_terminated(subreq, error ?: req->actual_len, false);
 
        }
 
        afs_drop_io_locks(op);
-
-       if (op->error == -ECONNABORTED)
-               op->error = afs_abort_to_error(op->ac.abort_code);
 }
 
 /*
        _enter("");
 
        while (afs_select_fileserver(op)) {
+               op->call_error = 0;
+               op->call_abort_code = 0;
                op->cb_s_break = op->server->cb_s_break;
                if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) &&
                    op->ops->issue_yfs_rpc)
                else if (op->ops->issue_afs_rpc)
                        op->ops->issue_afs_rpc(op);
                else
-                       op->ac.error = -ENOTSUPP;
+                       op->call_error = -ENOTSUPP;
 
                if (op->call) {
                        afs_wait_for_call_to_complete(op->call, &op->ac);
-                       op->error = op->ac.error;
+                       op->call_abort_code = op->call->abort_code;
+                       op->call_error = op->call->error;
+                       op->call_responded = op->call->responded;
+                       op->ac.call_responded = true;
+                       WRITE_ONCE(op->ac.alist->addrs[op->ac.index].last_error,
+                                  op->call_error);
                        afs_put_call(op->call);
                }
        }
 
-       switch (op->error) {
-       case 0:
+       if (!afs_op_error(op)) {
                _debug("success");
                op->ops->success(op);
-               break;
-       case -ECONNABORTED:
+       } else if (op->cumul_error.aborted) {
                if (op->ops->aborted)
                        op->ops->aborted(op);
-               fallthrough;
-       default:
+       } else {
                if (op->ops->failed)
                        op->ops->failed(op);
-               break;
        }
 
        afs_end_vnode_operation(op);
 
        call->server = afs_use_server(server, afs_server_trace_give_up_cb);
        afs_make_call(ac, call, GFP_NOFS);
        afs_wait_for_call_to_complete(call, ac);
+       ret = call->error;
        afs_put_call(call);
        return ret;
 }
 
 struct afs_address {
        struct rxrpc_peer       *peer;
        u16                     service_id;
+       short                   last_error;     /* Last error from this address */
 };
 
 /*
        };
        void                    *buffer;        /* reply receive buffer */
        union {
-               long                    ret0;   /* Value to reply with instead of 0 */
                struct afs_addr_list    *ret_alist;
                struct afs_vldb_entry   *ret_vldb;
                char                    *ret_str;
        bool                    upgrade;        /* T to request service upgrade */
        bool                    intr;           /* T if interruptible */
        bool                    unmarshalling_error; /* T if an unmarshalling error occurred */
+       bool                    responded;      /* Got a response from the call (may be abort) */
        u16                     service_id;     /* Actual service ID (after upgrade) */
        unsigned int            debug_id;       /* Trace ID */
        u32                     operation_ID;   /* operation ID for an incoming call */
  * Error prioritisation and accumulation.
  */
 struct afs_error {
-       short   error;                  /* Accumulated error */
+       s32     abort_code;             /* Cumulative abort code */
+       short   error;                  /* Cumulative error */
        bool    responded;              /* T if server responded */
+       bool    aborted;                /* T if ->error is from an abort */
 };
 
 /*
        struct afs_addr_list    *alist;         /* Current address list (pins ref) */
        unsigned long           tried;          /* Tried addresses */
        signed char             index;          /* Current address */
-       bool                    responded;      /* T if the current address responded */
        unsigned short          nr_iterations;  /* Number of address iterations */
-       short                   error;
-       u32                     abort_code;
+       bool                    call_responded;
 };
 
 /*
        struct afs_vlserver     *server;        /* Server on which this resides */
        struct key              *key;           /* Key for the server */
        unsigned long           untried;        /* Bitmask of untried servers */
+       struct afs_error        cumul_error;    /* Cumulative error */
+       s32                     call_abort_code;
        short                   index;          /* Current server */
-       short                   error;
+       short                   call_error;     /* Error from single call */
        unsigned short          flags;
 #define AFS_VL_CURSOR_STOP     0x0001          /* Set to cease iteration */
 #define AFS_VL_CURSOR_RETRY    0x0002          /* Set to do a retry */
 #define AFS_VL_CURSOR_RETRIED  0x0004          /* Set if started a retry */
-       unsigned short          nr_iterations;  /* Number of server iterations */
+       short                   nr_iterations;  /* Number of server iterations */
+       bool                    call_responded; /* T if the current address responded */
 };
 
 /*
        struct dentry           *dentry_2;      /* Second dentry to be altered */
        struct timespec64       mtime;          /* Modification time to record */
        struct timespec64       ctime;          /* Change time to set */
+       struct afs_error        cumul_error;    /* Cumulative error */
        short                   nr_files;       /* Number of entries in file[], more_files */
-       short                   error;
+       short                   call_error;     /* Error from single call */
+       s32                     call_abort_code; /* Abort code from single call */
        unsigned int            debug_id;
 
        unsigned int            cb_v_break;     /* Volume break counter before op */
        unsigned long           untried;        /* Bitmask of untried servers */
        short                   index;          /* Current server */
        short                   nr_iterations;  /* Number of server iterations */
+       bool                    call_responded; /* T if the current address responded */
+
 
        unsigned int            flags;
 #define AFS_OPERATION_STOP             0x0001  /* Set to cease iteration */
                        const struct afs_addr_list *b);
 extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);
 extern bool afs_iterate_addresses(struct afs_addr_cursor *);
-extern int afs_end_cursor(struct afs_addr_cursor *);
+extern void afs_end_cursor(struct afs_addr_cursor *ac);
 
 extern int afs_merge_fs_addr4(struct afs_net *net, struct afs_addr_list *addr,
                              __be32 xdr, u16 port);
 
 static inline void afs_op_nomem(struct afs_operation *op)
 {
-       op->error = -ENOMEM;
+       op->cumul_error.error = -ENOMEM;
 }
 
 static inline int afs_op_error(const struct afs_operation *op)
 {
-       return op->error;
+       return op->cumul_error.error;
+}
+
+static inline s32 afs_op_abort_code(const struct afs_operation *op)
+{
+       return op->cumul_error.abort_code;
 }
 
 static inline int afs_op_set_error(struct afs_operation *op, int error)
 {
-       return op->error = error;
+       return op->cumul_error.error = error;
+}
+
+static inline void afs_op_accumulate_error(struct afs_operation *op, int error, s32 abort_code)
+{
+       afs_prioritise_error(&op->cumul_error, error, abort_code);
 }
 
 /*
                                             struct afs_vnode_param *dir_vp,
                                             struct dentry *dentry)
 {
-       if (!op->error)
+       if (!op->cumul_error.error)
                dentry->d_fsdata =
                        (void *)(unsigned long)dir_vp->scb.status.data_version;
 }
 
 {
        switch (error) {
        case 0:
+               e->aborted = false;
+               e->error = 0;
                return;
        default:
                if (e->error == -ETIMEDOUT ||
                if (e->responded)
                        return;
                e->error = error;
+               e->aborted = false;
                return;
 
        case -ECONNABORTED:
-               error = afs_abort_to_error(abort_code);
-               fallthrough;
+               e->error = afs_abort_to_error(abort_code);
+               e->aborted = true;
+               e->responded = true;
+               return;
        case -ENETRESET: /* Responded, but we seem to have changed address */
+               e->aborted = false;
                e->responded = true;
                e->error = error;
                return;
 
        struct afs_addr_list *alist;
        struct afs_server *server;
        struct afs_vnode *vnode = op->file[0].vnode;
-       struct afs_error e;
        unsigned int rtt;
-       int error = op->ac.error, i;
+       s32 abort_code = op->call_abort_code;
+       int error = op->call_error, i;
 
        op->nr_iterations++;
 
               op->debug_id, op->nr_iterations, op->volume->vid,
               op->untried, op->index,
               op->ac.tried, op->ac.index,
-              error, op->ac.abort_code);
+              error, abort_code);
 
        if (op->flags & AFS_OPERATION_STOP) {
                _leave(" = f [stopped]");
                goto start;
 
        /* Evaluate the result of the previous operation, if there was one. */
-       switch (error) {
+       switch (op->call_error) {
        case 0:
+               op->cumul_error.responded = true;
+               fallthrough;
        default:
                /* Success or local failure.  Stop. */
                afs_op_set_error(op, error);
                 * errors instead.  IBM AFS and OpenAFS fileservers, however, do leak
                 * these abort codes.
                 */
-               switch (op->ac.abort_code) {
+               op->cumul_error.responded = true;
+               switch (abort_code) {
                case VNOVOL:
                        /* This fileserver doesn't know about the volume.
                         * - May indicate that the VL is wrong - retry once and compare
                         *   (administrative action).
                         */
                        if (op->flags & AFS_OPERATION_VNOVOL) {
-                               op->error = -EREMOTEIO;
+                               afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
                                goto next_server;
                        }
 
                         * it's the fileserver having trouble.
                         */
                        if (rcu_access_pointer(op->volume->servers) == op->server_list) {
-                               op->error = -EREMOTEIO;
+                               afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
                                goto next_server;
                        }
 
                case VONLINE:
                        /* These should not be returned from the fileserver. */
                        pr_warn("Fileserver returned unexpected abort %d\n",
-                               op->ac.abort_code);
-                       op->error = -EREMOTEIO;
+                               abort_code);
+                       afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
                        goto next_server;
 
                case VNOSERVICE:
                         * VNOSERVICE should be treated as an alias for RX_CALL_TIMEOUT.
                         */
                case RX_CALL_TIMEOUT:
-                       op->error = -ETIMEDOUT;
+                       afs_op_accumulate_error(op, -ETIMEDOUT, abort_code);
                        goto next_server;
 
                case VSALVAGING: /* This error should not be leaked to cache managers
                         * days).
                         */
                        if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &op->volume->flags)) {
-                               afs_busy(op->volume, op->ac.abort_code);
+                               afs_busy(op->volume, abort_code);
                                clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
                        }
                        if (op->flags & AFS_OPERATION_NO_VSLEEP) {
                                goto failed;
                        }
                        if (!test_and_set_bit(AFS_VOLUME_BUSY, &op->volume->flags)) {
-                               afs_busy(op->volume, op->ac.abort_code);
+                               afs_busy(op->volume, abort_code);
                                clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
                        }
                busy:
                         * TODO: Retry a few times with sleeps.
                         */
                        if (rcu_access_pointer(op->volume->servers) == op->server_list) {
-                               op->error = -ENOMEDIUM;
+                               afs_op_accumulate_error(op, -ENOMEDIUM, abort_code);
                                goto failed;
                        }
 
 
                case UAEIO:
                case VIO:
-                       op->error = -EREMOTEIO;
+                       afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
                        if (op->volume->type != AFSVL_RWVOL)
                                goto next_server;
                        goto failed;
                        goto failed_but_online;
 
                default:
-                       op->error = afs_abort_to_error(op->ac.abort_code);
+                       afs_op_accumulate_error(op, error, abort_code);
                failed_but_online:
                        clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags);
                        clear_bit(AFS_VOLUME_BUSY, &op->volume->flags);
        case -EHOSTDOWN:
        case -ECONNREFUSED:
                _debug("no conn");
-               op->error = error;
+               afs_op_accumulate_error(op, error, 0);
                goto iterate_address;
 
        case -ENETRESET:
               op->index, op->ac.index, op->ac.alist->nr_addrs,
               rxrpc_kernel_remote_addr(op->ac.alist->addrs[op->ac.index].peer));
 
+       op->call_responded = false;
        _leave(" = t");
        return true;
 
        if (op->flags & AFS_OPERATION_VBUSY)
                goto restart_from_beginning;
 
-       e.error = -EDESTADDRREQ;
-       e.responded = false;
        for (i = 0; i < op->server_list->nr_servers; i++) {
                struct afs_server *s = op->server_list->servers[i].server;
 
-               afs_prioritise_error(&e, READ_ONCE(s->probe.error),
-                                    s->probe.abort_code);
+               error = READ_ONCE(s->probe.error);
+               if (error < 0)
+                       afs_op_accumulate_error(op, error, s->probe.abort_code);
        }
 
-       error = e.error;
-       op->error = error;
 failed:
        op->flags |= AFS_OPERATION_STOP;
        afs_end_cursor(&op->ac);
        rcu_read_lock();
 
        pr_notice("EDESTADDR occurred\n");
-       pr_notice("FC: cbb=%x cbb2=%x fl=%x err=%hd\n",
+       pr_notice("OP: cbb=%x cbb2=%x fl=%x err=%hd\n",
                  op->file[0].cb_break_before,
-                 op->file[1].cb_break_before, op->flags, op->error);
-       pr_notice("FC: ut=%lx ix=%d ni=%u\n",
+                 op->file[1].cb_break_before, op->flags, op->cumul_error.error);
+       pr_notice("OP: ut=%lx ix=%d ni=%u\n",
                  op->untried, op->index, op->nr_iterations);
+       pr_notice("OP: call  er=%d ac=%d r=%u\n",
+                 op->call_error, op->call_abort_code, op->call_responded);
 
        if (op->server_list) {
                const struct afs_server_list *sl = op->server_list;
                }
        }
 
-       pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
-                 op->ac.tried, op->ac.index, op->ac.abort_code, op->ac.error,
-                 op->ac.responded, op->ac.nr_iterations);
+       pr_notice("AC: t=%lx ax=%u ni=%u\n",
+                 op->ac.tried, op->ac.index, op->ac.nr_iterations);
        rcu_read_unlock();
 }
 
                rxrpc_kernel_recv_data(call->net->socket, rxcall,
                                       &msg.msg_iter, &len, false,
                                       &call->abort_code, &call->service_id);
-               ac->abort_code = call->abort_code;
-               ac->responded = true;
+               call->responded = true;
        }
        call->error = ret;
        trace_afs_call_done(call);
                afs_set_call_complete(call, ret, 0);
        }
 
-       ac->error = ret;
+       call->error = ret;
        call->state = AFS_CALL_COMPLETE;
        _leave(" = %d", ret);
 }
                        ret = -EBADMSG;
                switch (ret) {
                case 0:
+                       call->responded = true;
                        afs_queue_call_work(call);
                        if (state == AFS_CALL_CL_PROC_REPLY) {
                                if (call->op)
                        goto out;
                case -ECONNABORTED:
                        ASSERTCMP(state, ==, AFS_CALL_COMPLETE);
+                       call->responded = true;
                        afs_log_error(call, call->abort_code);
                        goto done;
                case -ENOTSUPP:
+                       call->responded = true;
                        abort_code = RXGEN_OPCODE;
                        rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
                                                abort_code, ret,
 }
 
 /*
- * Wait synchronously for a call to complete and clean up the call struct.
+ * Wait synchronously for a call to complete.
  */
 void afs_wait_for_call_to_complete(struct afs_call *call, struct afs_addr_cursor *ac)
 {
                }
        }
 
-       spin_lock_bh(&call->state_lock);
-       ac->abort_code = call->abort_code;
-       ac->error = call->error;
-       spin_unlock_bh(&call->state_lock);
-
        if (call->error == 0 || call->error == -ECONNABORTED)
-               ac->responded = true;
+               call->responded = true;
 }
 
 /*
 
        struct afs_addr_cursor ac = {
                .alist  = alist,
                .index  = alist->preferred,
-               .error  = 0,
        };
 
        afs_fs_give_up_all_callbacks(net, server, &ac, NULL);
 
 
        while (afs_select_vlserver(&vc)) {
                if (!test_bit(AFS_VLSERVER_FL_IS_YFS, &vc.server->flags)) {
-                       vc.ac.error = -EOPNOTSUPP;
+                       vc.call_error = -EOPNOTSUPP;
                        skipped = true;
                        continue;
                }
 
                call = afs_vl_get_capabilities(net, &ac, key, server,
                                               server_index);
                if (!IS_ERR(call)) {
+                       afs_prioritise_error(_e, call->error, call->abort_code);
                        afs_put_call(call);
                        in_progress = true;
                } else {
-                       afs_prioritise_error(_e, PTR_ERR(call), ac.abort_code);
+                       afs_prioritise_error(_e, PTR_ERR(call), 0);
                        afs_done_one_vl_probe(server, false);
                }
        }
                       struct afs_vlserver_list *vllist)
 {
        struct afs_vlserver *server;
-       struct afs_error e;
+       struct afs_error e = {};
        bool in_progress = false;
        int i;
 
-       e.error = 0;
-       e.responded = false;
        for (i = 0; i < vllist->nr_servers; i++) {
                server = vllist->servers[i].server;
                if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags))
 
        memset(vc, 0, sizeof(*vc));
        vc->cell = cell;
        vc->key = key;
-       vc->error = -EDESTADDRREQ;
-       vc->ac.error = SHRT_MAX;
+       vc->cumul_error.error = -EDESTADDRREQ;
+       vc->nr_iterations = -1;
 
        if (signal_pending(current)) {
-               vc->error = -EINTR;
+               vc->cumul_error.error = -EINTR;
                vc->flags |= AFS_VL_CURSOR_STOP;
                return false;
        }
                                    &cell->dns_lookup_count,
                                    smp_load_acquire(&cell->dns_lookup_count)
                                    != dns_lookup_count) < 0) {
-                               vc->error = -ERESTARTSYS;
+                               vc->cumul_error.error = -ERESTARTSYS;
                                return false;
                        }
                }
                /* Status load is ordered after lookup counter load */
                if (cell->dns_status == DNS_LOOKUP_GOT_NOT_FOUND) {
                        pr_warn("No record of cell %s\n", cell->name);
-                       vc->error = -ENOENT;
+                       vc->cumul_error.error = -ENOENT;
                        return false;
                }
 
                if (cell->dns_source == DNS_RECORD_UNAVAILABLE) {
-                       vc->error = -EDESTADDRREQ;
+                       vc->cumul_error.error = -EDESTADDRREQ;
                        return false;
                }
        }
 {
        struct afs_addr_list *alist;
        struct afs_vlserver *vlserver;
-       struct afs_error e;
        unsigned int rtt;
-       int error = vc->ac.error, i;
+       s32 abort_code = vc->call_abort_code;
+       int error = vc->call_error, i;
+
+       vc->nr_iterations++;
 
        _enter("%lx[%d],%lx[%d],%d,%d",
               vc->untried, vc->index,
               vc->ac.tried, vc->ac.index,
-              error, vc->ac.abort_code);
+              error, abort_code);
 
        if (vc->flags & AFS_VL_CURSOR_STOP) {
                _leave(" = f [stopped]");
                return false;
        }
 
-       vc->nr_iterations++;
+       if (vc->nr_iterations == 0)
+               goto start;
 
        /* Evaluate the result of the previous operation, if there was one. */
        switch (error) {
-       case SHRT_MAX:
-               goto start;
-
        default:
        case 0:
                /* Success or local failure.  Stop. */
-               vc->error = error;
+               vc->cumul_error.error = error;
                vc->flags |= AFS_VL_CURSOR_STOP;
-               _leave(" = f [okay/local %d]", vc->ac.error);
+               _leave(" = f [okay/local %d]", vc->cumul_error.error);
                return false;
 
        case -ECONNABORTED:
                /* The far side rejected the operation on some grounds.  This
                 * might involve the server being busy or the volume having been moved.
                 */
-               switch (vc->ac.abort_code) {
+               switch (abort_code) {
                case AFSVL_IO:
                case AFSVL_BADVOLOPER:
                case AFSVL_NOMEM:
                        /* The server went weird. */
-                       vc->error = -EREMOTEIO;
+                       afs_prioritise_error(&vc->cumul_error, -EREMOTEIO, abort_code);
                        //write_lock(&vc->cell->vl_servers_lock);
                        //vc->server_list->weird_mask |= 1 << vc->index;
                        //write_unlock(&vc->cell->vl_servers_lock);
                        goto next_server;
 
                default:
-                       vc->error = afs_abort_to_error(vc->ac.abort_code);
+                       afs_prioritise_error(&vc->cumul_error, error, abort_code);
                        goto failed;
                }
 
        case -ETIMEDOUT:
        case -ETIME:
                _debug("no conn %d", error);
-               vc->error = error;
+               afs_prioritise_error(&vc->cumul_error, error, 0);
                goto iterate_address;
 
        case -ECONNRESET:
                _debug("call reset");
-               vc->error = error;
+               afs_prioritise_error(&vc->cumul_error, error, 0);
                vc->flags |= AFS_VL_CURSOR_RETRY;
                goto next_server;
 
                goto failed;
 
        error = afs_send_vl_probes(vc->cell->net, vc->key, vc->server_list);
-       if (error < 0)
-               goto failed_set_error;
+       if (error < 0) {
+               afs_prioritise_error(&vc->cumul_error, error, 0);
+               goto failed;
+       }
 
 pick_server:
        _debug("pick [%lx]", vc->untried);
 
        error = afs_wait_for_vl_probes(vc->server_list, vc->untried);
-       if (error < 0)
-               goto failed_set_error;
+       if (error < 0) {
+               afs_prioritise_error(&vc->cumul_error, error, 0);
+               goto failed;
+       }
 
        /* Pick the untried server with the lowest RTT. */
        vc->index = vc->server_list->preferred;
 
        _debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs);
 
+       vc->call_responded = false;
        _leave(" = t %pISpc", rxrpc_kernel_remote_addr(vc->ac.alist->addrs[vc->ac.index].peer));
        return true;
 
        if (vc->flags & AFS_VL_CURSOR_RETRY)
                goto restart_from_beginning;
 
-       e.error = -EDESTADDRREQ;
-       e.responded = false;
        for (i = 0; i < vc->server_list->nr_servers; i++) {
                struct afs_vlserver *s = vc->server_list->servers[i].server;
 
                if (test_bit(AFS_VLSERVER_FL_RESPONDING, &s->flags))
-                       e.responded = true;
-               afs_prioritise_error(&e, READ_ONCE(s->probe.error),
+                       vc->cumul_error.responded = true;
+               afs_prioritise_error(&vc->cumul_error, READ_ONCE(s->probe.error),
                                     s->probe.abort_code);
        }
 
-       error = e.error;
-
-failed_set_error:
-       vc->error = error;
 failed:
        vc->flags |= AFS_VL_CURSOR_STOP;
        afs_end_cursor(&vc->ac);
-       _leave(" = f [failed %d]", vc->error);
+       _leave(" = f [failed %d]", vc->cumul_error.error);
        return false;
 }
 
        pr_notice("DNS: src=%u st=%u lc=%x\n",
                  cell->dns_source, cell->dns_status, cell->dns_lookup_count);
        pr_notice("VC: ut=%lx ix=%u ni=%hu fl=%hx err=%hd\n",
-                 vc->untried, vc->index, vc->nr_iterations, vc->flags, vc->error);
+                 vc->untried, vc->index, vc->nr_iterations, vc->flags,
+                 vc->cumul_error.error);
+       pr_notice("VC: call  er=%d ac=%d r=%u\n",
+                 vc->call_error, vc->call_abort_code, vc->call_responded);
 
        if (vc->server_list) {
                const struct afs_vlserver_list *sl = vc->server_list;
                }
        }
 
-       pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n",
-                 vc->ac.tried, vc->ac.index, vc->ac.abort_code, vc->ac.error,
-                 vc->ac.responded, vc->ac.nr_iterations);
+       pr_notice("AC: t=%lx ax=%u ni=%u\n",
+                 vc->ac.tried, vc->ac.index, vc->ac.nr_iterations);
        rcu_read_unlock();
 }
 
 {
        struct afs_net *net = vc->cell->net;
 
-       if (vc->error == -EDESTADDRREQ ||
-           vc->error == -EADDRNOTAVAIL ||
-           vc->error == -ENETUNREACH ||
-           vc->error == -EHOSTUNREACH)
+       switch (vc->cumul_error.error) {
+       case -EDESTADDRREQ:
+       case -EADDRNOTAVAIL:
+       case -ENETUNREACH:
+       case -EHOSTUNREACH:
                afs_vl_dump_edestaddrreq(vc);
+               break;
+       }
 
        afs_end_cursor(&vc->ac);
        afs_put_vlserverlist(net, vc->server_list);
-
-       if (vc->error == -ECONNABORTED)
-               vc->error = afs_abort_to_error(vc->ac.abort_code);
-
-       return vc->error;
+       return vc->cumul_error.error;
 }
 
        trace_afs_make_vl_call(call);
        afs_make_call(&vc->ac, call, GFP_KERNEL);
        afs_wait_for_call_to_complete(call, &vc->ac);
+       vc->call_abort_code     = call->abort_code;
+       vc->call_error          = call->error;
+       vc->call_responded      = call->responded;
        afs_put_call(call);
-       if (vc->ac.error) {
+       if (vc->call_error) {
                kfree(entry);
-               return ERR_PTR(vc->ac.error);
+               return ERR_PTR(vc->call_error);
        }
        return entry;
 }
        trace_afs_make_vl_call(call);
        afs_make_call(&vc->ac, call, GFP_KERNEL);
        afs_wait_for_call_to_complete(call, &vc->ac);
-       alist = call->ret_alist;
+       vc->call_abort_code     = call->abort_code;
+       vc->call_error          = call->error;
+       vc->call_responded      = call->responded;
+       alist                   = call->ret_alist;
        afs_put_call(call);
-       if (vc->ac.error) {
+       if (vc->call_error) {
                afs_put_addrlist(alist);
-               return ERR_PTR(vc->ac.error);
+               return ERR_PTR(vc->call_error);
        }
        return alist;
 }
        trace_afs_make_vl_call(call);
        afs_make_call(&vc->ac, call, GFP_KERNEL);
        afs_wait_for_call_to_complete(call, &vc->ac);
-       alist = call->ret_alist;
+       vc->call_abort_code     = call->abort_code;
+       vc->call_error          = call->error;
+       vc->call_responded      = call->responded;
+       alist                   = call->ret_alist;
        afs_put_call(call);
-       if (vc->ac.error) {
+       if (vc->call_error) {
                afs_put_addrlist(alist);
-               return ERR_PTR(vc->ac.error);
+               return ERR_PTR(vc->call_error);
        }
        return alist;
 }
        trace_afs_make_vl_call(call);
        afs_make_call(&vc->ac, call, GFP_KERNEL);
        afs_wait_for_call_to_complete(call, &vc->ac);
-       cellname = call->ret_str;
+       vc->call_abort_code     = call->abort_code;
+       vc->call_error          = call->error;
+       vc->call_responded      = call->responded;
+       cellname                = call->ret_str;
        afs_put_call(call);
-       if (vc->ac.error) {
+       if (vc->call_error) {
                kfree(cellname);
-               return ERR_PTR(vc->ac.error);
+               return ERR_PTR(vc->call_error);
        }
        return cellname;
 }