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 b76abf5007134769d89e7c96b59006390606b00d..a1f3c995e328c2da32f84a8f61fef80dc8c2c233 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 b40f7ae850a830d7a3700e1ea3eed4d4fa37d91d..ecb889a269fb9315a46c21d46b15c19e05d483c9 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 bb5807e87fa4c430d6be36f6e1754aa62f5c11b9..a1e581946b93000ade2de2efd6a66eb3667520cc 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 0c81c39c32f52b392fc88b069b9aec067474a9a8..8f9b424275698630fb6dc8228243e2d7a8368fd5 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 1c22d6e778460e7a44170f3a0b21d80a4f386ebf..cebe4fad81922658314ec108a625f1e3ff9ca718 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 020073387111734602165f3f323c682455cb9c5e..2a56dea22519081670a2b5591a459f4788873714 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 1bc69a115223f375515a518ecd0465a4e3ab0a48..d67c75d4d2bdd2a1f2ea85bf4463cd1826bcb22d 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 805328ca54284286e2e95608b41d841a70b05caa..b8180bf2281f7214e4d52abe4590e6f5ecb5c3b8 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 965ee8f0804a909db264d13d0c26df7b705a1bcf..a778d53681fe0e177f3bb443c73b6923fbdc60b6 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 dad8efadbc441aa47a17ab061d2868d2b0517860..0b3e2f20b0e082d54c868bf866d9ce0cc7f321ee 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 2826e6eced71bce9603af2aedcec9b3c1353a210..f7791ef13618ab53ebfa21e238882e07925e16c5 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 6fdf9f1bedc0f4df67e79d49212a73101111126f..89cadd9a69e12b2e710e743d32f0dcd80aba3863 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 44bff3a2a5acad3d1834ebb0ed5ce515dbd15ba9..138f5715619d0f0d2b5a37ac5002dee3b4fbcca1 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 01c890b3d18d9fa06fc2df4412d90166f6f29624..7ae73418697dfa6f1b137fe9ec73740a1f9f066c 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 650534892a20250b07427b9e0b1e785cd5a8bf06..db7e94584e874643d07ecf897bfc00d5c843fd31 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;
 }