kfree(aead_req);
 
+       spin_lock_bh(&ctx->decrypt_compl_lock);
        pending = atomic_dec_return(&ctx->decrypt_pending);
 
-       if (!pending && READ_ONCE(ctx->async_notify))
+       if (!pending && ctx->async_notify)
                complete(&ctx->async_wait.completion);
+       spin_unlock_bh(&ctx->decrypt_compl_lock);
 }
 
 static int tls_do_decryption(struct sock *sk,
                        ready = true;
        }
 
+       spin_lock_bh(&ctx->encrypt_compl_lock);
        pending = atomic_dec_return(&ctx->encrypt_pending);
 
-       if (!pending && READ_ONCE(ctx->async_notify))
+       if (!pending && ctx->async_notify)
                complete(&ctx->async_wait.completion);
+       spin_unlock_bh(&ctx->encrypt_compl_lock);
 
        if (!ready)
                return;
        int num_zc = 0;
        int orig_size;
        int ret = 0;
+       int pending;
 
        if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL))
                return -EOPNOTSUPP;
                goto send_end;
        } else if (num_zc) {
                /* Wait for pending encryptions to get completed */
-               smp_store_mb(ctx->async_notify, true);
+               spin_lock_bh(&ctx->encrypt_compl_lock);
+               ctx->async_notify = true;
 
-               if (atomic_read(&ctx->encrypt_pending))
+               pending = atomic_read(&ctx->encrypt_pending);
+               spin_unlock_bh(&ctx->encrypt_compl_lock);
+               if (pending)
                        crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
                else
                        reinit_completion(&ctx->async_wait.completion);
 
+               /* There can be no concurrent accesses, since we have no
+                * pending encrypt operations
+                */
                WRITE_ONCE(ctx->async_notify, false);
 
                if (ctx->async_wait.err) {
        bool is_kvec = iov_iter_is_kvec(&msg->msg_iter);
        bool is_peek = flags & MSG_PEEK;
        int num_async = 0;
+       int pending;
 
        flags |= nonblock;
 
 recv_end:
        if (num_async) {
                /* Wait for all previously submitted records to be decrypted */
-               smp_store_mb(ctx->async_notify, true);
-               if (atomic_read(&ctx->decrypt_pending)) {
+               spin_lock_bh(&ctx->decrypt_compl_lock);
+               ctx->async_notify = true;
+               pending = atomic_read(&ctx->decrypt_pending);
+               spin_unlock_bh(&ctx->decrypt_compl_lock);
+               if (pending) {
                        err = crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
                        if (err) {
                                /* one of async decrypt failed */
                } else {
                        reinit_completion(&ctx->async_wait.completion);
                }
+
+               /* There can be no concurrent accesses, since we have no
+                * pending decrypt operations
+                */
                WRITE_ONCE(ctx->async_notify, false);
 
                /* Drain records from the rx_list & copy if required */
 
        if (tx) {
                crypto_init_wait(&sw_ctx_tx->async_wait);
+               spin_lock_init(&sw_ctx_tx->encrypt_compl_lock);
                crypto_info = &ctx->crypto_send.info;
                cctx = &ctx->tx;
                aead = &sw_ctx_tx->aead_send;
                sw_ctx_tx->tx_work.sk = sk;
        } else {
                crypto_init_wait(&sw_ctx_rx->async_wait);
+               spin_lock_init(&sw_ctx_rx->decrypt_compl_lock);
                crypto_info = &ctx->crypto_recv.info;
                cctx = &ctx->rx;
                skb_queue_head_init(&sw_ctx_rx->rx_list);