afs: Simplify error handling
authorDavid Howells <dhowells@redhat.com>
Wed, 25 Oct 2023 16:53:33 +0000 (17:53 +0100)
committerDavid Howells <dhowells@redhat.com>
Sun, 24 Dec 2023 15:22:53 +0000 (15:22 +0000)
Simplify error handling a bit by moving it from the afs_addr_cursor struct
to the afs_operation and afs_vl_cursor structs and using the error
prioritisation function for accumulating errors from multiple sources (AFS
tries to rotate between multiple fileservers, some of which may be
inaccessible or in some state of offlinedness).

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org

15 files changed:
fs/afs/addr_list.c
fs/afs/dir.c
fs/afs/dir_silly.c
fs/afs/file.c
fs/afs/fs_operation.c
fs/afs/fsclient.c
fs/afs/internal.h
fs/afs/misc.c
fs/afs/rotate.c
fs/afs/rxrpc.c
fs/afs/server.c
fs/afs/vl_alias.c
fs/afs/vl_probe.c
fs/afs/vl_rotate.c
fs/afs/vlclient.c

index b76abf5..a1f3c99 100644 (file)
@@ -386,26 +386,24 @@ bool afs_iterate_addresses(struct afs_addr_cursor *ac)
 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;
 }
index b40f7ae..ecb889a 100644 (file)
@@ -693,8 +693,9 @@ static void afs_do_lookup_success(struct afs_operation *op)
                        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;
 
@@ -846,13 +847,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
        _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];
@@ -1255,7 +1257,7 @@ void afs_check_for_remote_deletion(struct afs_operation *op)
 {
        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);
@@ -1280,7 +1282,7 @@ static void afs_vnode_new_inode(struct afs_operation *op)
                /* 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;
        }
 
index bb5807e..a1e5819 100644 (file)
@@ -218,7 +218,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode
        /* 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;
index 0c81c39..8f9b424 100644 (file)
@@ -245,10 +245,7 @@ static void afs_fetch_data_notify(struct afs_operation *op)
        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);
index 1c22d6e..cebe4fa 100644 (file)
@@ -169,9 +169,6 @@ static void afs_end_vnode_operation(struct afs_operation *op)
        }
 
        afs_drop_io_locks(op);
-
-       if (op->error == -ECONNABORTED)
-               op->error = afs_abort_to_error(op->ac.abort_code);
 }
 
 /*
@@ -182,6 +179,8 @@ void afs_wait_for_operation(struct afs_operation *op)
        _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)
@@ -189,28 +188,29 @@ void afs_wait_for_operation(struct afs_operation *op)
                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);
index 0200733..2a56dea 100644 (file)
@@ -1629,6 +1629,7 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net,
        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;
 }
index 1bc69a1..d67c75d 100644 (file)
@@ -75,6 +75,7 @@ enum afs_call_state {
 struct afs_address {
        struct rxrpc_peer       *peer;
        u16                     service_id;
+       short                   last_error;     /* Last error from this address */
 };
 
 /*
@@ -121,7 +122,6 @@ struct afs_call {
        };
        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;
@@ -145,6 +145,7 @@ struct afs_call {
        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 */
@@ -719,8 +720,10 @@ struct afs_permits {
  * 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 */
 };
 
 /*
@@ -730,10 +733,8 @@ struct afs_addr_cursor {
        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;
 };
 
 /*
@@ -746,13 +747,16 @@ struct afs_vl_cursor {
        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 */
 };
 
 /*
@@ -803,8 +807,10 @@ struct afs_operation {
        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 */
@@ -860,6 +866,8 @@ struct afs_operation {
        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 */
@@ -976,7 +984,7 @@ bool afs_addr_list_same(const struct afs_addr_list *a,
                        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);
@@ -1235,17 +1243,27 @@ extern void afs_prioritise_error(struct afs_error *, int, u32);
 
 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);
 }
 
 /*
@@ -1619,7 +1637,7 @@ static inline void afs_update_dentry_version(struct afs_operation *op,
                                             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;
 }
index 805328c..b8180bf 100644 (file)
@@ -116,6 +116,8 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
 {
        switch (error) {
        case 0:
+               e->aborted = false;
+               e->error = 0;
                return;
        default:
                if (e->error == -ETIMEDOUT ||
@@ -161,12 +163,16 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
                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;
index 965ee8f..a778d53 100644 (file)
@@ -112,9 +112,9 @@ bool afs_select_fileserver(struct afs_operation *op)
        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++;
 
@@ -122,7 +122,7 @@ bool afs_select_fileserver(struct afs_operation *op)
               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]");
@@ -133,8 +133,10 @@ bool afs_select_fileserver(struct afs_operation *op)
                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);
@@ -151,7 +153,8 @@ bool afs_select_fileserver(struct afs_operation *op)
                 * 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
@@ -164,7 +167,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                         *   (administrative action).
                         */
                        if (op->flags & AFS_OPERATION_VNOVOL) {
-                               op->error = -EREMOTEIO;
+                               afs_op_accumulate_error(op, -EREMOTEIO, abort_code);
                                goto next_server;
                        }
 
@@ -188,7 +191,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                         * 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;
                        }
 
@@ -201,8 +204,8 @@ bool afs_select_fileserver(struct afs_operation *op)
                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:
@@ -233,7 +236,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                         * 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
@@ -248,7 +251,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                         * 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) {
@@ -281,7 +284,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                                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:
@@ -329,7 +332,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                         * 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;
                        }
 
@@ -337,7 +340,7 @@ bool afs_select_fileserver(struct afs_operation *op)
 
                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;
@@ -361,7 +364,7 @@ bool afs_select_fileserver(struct afs_operation *op)
                        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);
@@ -380,7 +383,7 @@ bool afs_select_fileserver(struct afs_operation *op)
        case -EHOSTDOWN:
        case -ECONNREFUSED:
                _debug("no conn");
-               op->error = error;
+               afs_op_accumulate_error(op, error, 0);
                goto iterate_address;
 
        case -ENETRESET:
@@ -506,6 +509,7 @@ iterate_address:
               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;
 
@@ -543,17 +547,14 @@ no_more_servers:
        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);
@@ -576,11 +577,13 @@ void afs_dump_edestaddrreq(const struct afs_operation *op)
        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;
@@ -605,8 +608,7 @@ void afs_dump_edestaddrreq(const struct afs_operation *op)
                }
        }
 
-       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();
 }
index dad8efa..0b3e2f2 100644 (file)
@@ -408,8 +408,7 @@ error_do_abort:
                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);
@@ -429,7 +428,7 @@ error_kill_call:
                afs_set_call_complete(call, ret, 0);
        }
 
-       ac->error = ret;
+       call->error = ret;
        call->state = AFS_CALL_COMPLETE;
        _leave(" = %d", ret);
 }
@@ -510,6 +509,7 @@ static void afs_deliver_to_call(struct afs_call *call)
                        ret = -EBADMSG;
                switch (ret) {
                case 0:
+                       call->responded = true;
                        afs_queue_call_work(call);
                        if (state == AFS_CALL_CL_PROC_REPLY) {
                                if (call->op)
@@ -524,9 +524,11 @@ static void afs_deliver_to_call(struct afs_call *call)
                        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,
@@ -573,7 +575,7 @@ call_complete:
 }
 
 /*
- * 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)
 {
@@ -626,13 +628,8 @@ void afs_wait_for_call_to_complete(struct afs_call *call, struct afs_addr_cursor
                }
        }
 
-       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;
 }
 
 /*
index 2826e6e..f7791ef 100644 (file)
@@ -437,7 +437,6 @@ static void afs_give_up_callbacks(struct afs_net *net, struct afs_server *server
        struct afs_addr_cursor ac = {
                .alist  = alist,
                .index  = alist->preferred,
-               .error  = 0,
        };
 
        afs_fs_give_up_all_callbacks(net, server, &ac, NULL);
index 6fdf9f1..89cadd9 100644 (file)
@@ -236,7 +236,7 @@ static char *afs_vl_get_cell_name(struct afs_cell *cell, struct key *key)
 
        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;
                }
index 44bff3a..138f571 100644 (file)
@@ -169,10 +169,11 @@ static bool afs_do_probe_vlserver(struct afs_net *net,
                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);
                }
        }
@@ -187,12 +188,10 @@ int afs_send_vl_probes(struct afs_net *net, struct key *key,
                       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))
index 01c890b..7ae7341 100644 (file)
@@ -20,11 +20,11 @@ bool afs_begin_vlserver_operation(struct afs_vl_cursor *vc, struct afs_cell *cel
        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;
        }
@@ -52,7 +52,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
                                    &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;
                        }
                }
@@ -60,12 +60,12 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc)
                /* 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;
                }
        }
@@ -91,52 +91,52 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
 {
        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;
                }
 
@@ -149,12 +149,12 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
        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;
 
@@ -178,15 +178,19 @@ start:
                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;
@@ -249,6 +253,7 @@ iterate_address:
 
        _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;
 
@@ -264,25 +269,19 @@ no_more_servers:
        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;
 }
 
@@ -305,7 +304,10 @@ static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
        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;
@@ -329,9 +331,8 @@ static void afs_vl_dump_edestaddrreq(const struct afs_vl_cursor *vc)
                }
        }
 
-       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();
 }
 
@@ -342,17 +343,16 @@ int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
 {
        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;
 }
index 6505348..db7e945 100644 (file)
@@ -161,10 +161,13 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,
        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;
 }
@@ -305,11 +308,14 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
        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;
 }
@@ -656,11 +662,14 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
        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;
 }
@@ -769,11 +778,14 @@ char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)
        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;
 }