#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/blktrace_api.h>
+#include <linux/types.h>
 #include <linux/slab.h>
 #include <scsi/fc/fc_els.h>
 #include "zfcp_ext.h"
 
 static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
 {
+       const bool is_srb = zfcp_fsf_req_is_status_read_buffer(req);
        struct zfcp_adapter *adapter = req->adapter;
        struct zfcp_qdio *qdio = adapter->qdio;
        int req_id = req->req_id;
                return -EIO;
        }
 
+       /*
+        * NOTE: DO NOT TOUCH ASYNC req PAST THIS POINT.
+        *       ONLY TOUCH SYNC req AGAIN ON req->completion.
+        *
+        * The request might complete and be freed concurrently at any point
+        * now. This is not protected by the QDIO-lock (req_q_lock). So any
+        * uncontrolled access after this might result in an use-after-free bug.
+        * Only if the request doesn't have ZFCP_STATUS_FSFREQ_CLEANUP set, and
+        * when it is completed via req->completion, is it safe to use req
+        * again.
+        */
+
        /* Don't increase for unsolicited status */
-       if (!zfcp_fsf_req_is_status_read_buffer(req))
+       if (!is_srb)
                adapter->fsf_req_seq_no++;
        adapter->req_no++;
 
        retval = zfcp_fsf_req_send(req);
        if (retval)
                goto failed_req_send;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
        req->qtcb->bottom.support.req_handle = (u64) old_req_id;
 
        zfcp_fsf_start_timer(req, ZFCP_FSF_SCSI_ER_TIMEOUT);
-       if (!zfcp_fsf_req_send(req))
+       if (!zfcp_fsf_req_send(req)) {
+               /* NOTE: DO NOT TOUCH req, UNTIL IT COMPLETES! */
                goto out;
+       }
 
 out_error_free:
        zfcp_fsf_req_free(req);
        ret = zfcp_fsf_req_send(req);
        if (ret)
                goto failed_send;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
        ret = zfcp_fsf_req_send(req);
        if (ret)
                goto failed_send;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
        zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
        retval = zfcp_fsf_req_send(req);
        spin_unlock_irq(&qdio->req_q_lock);
-       if (!retval)
+       if (!retval) {
+               /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */
                wait_for_completion(&req->completion);
+       }
 
        zfcp_fsf_req_free(req);
        return retval;
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
        retval = zfcp_fsf_req_send(req);
        spin_unlock_irq(&qdio->req_q_lock);
 
-       if (!retval)
+       if (!retval) {
+               /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */
                wait_for_completion(&req->completion);
+       }
 
        zfcp_fsf_req_free(req);
 
                erp_action->fsf_req_id = 0;
                put_device(&port->dev);
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
        retval = zfcp_fsf_req_send(req);
        if (retval)
                zfcp_fsf_req_free(req);
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        if (!retval)
        retval = zfcp_fsf_req_send(req);
        if (retval)
                zfcp_fsf_req_free(req);
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        if (!retval)
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
                zfcp_fsf_req_free(req);
                erp_action->fsf_req_id = 0;
        }
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 out:
        spin_unlock_irq(&qdio->req_q_lock);
        return retval;
        retval = zfcp_fsf_req_send(req);
        if (unlikely(retval))
                goto failed_scsi_cmnd;
+       /* NOTE: DO NOT TOUCH req PAST THIS POINT! */
 
        goto out;
 
        zfcp_fc_fcp_tm(fcp_cmnd, sdev, tm_flags);
 
        zfcp_fsf_start_timer(req, ZFCP_FSF_SCSI_ER_TIMEOUT);
-       if (!zfcp_fsf_req_send(req))
+       if (!zfcp_fsf_req_send(req)) {
+               /* NOTE: DO NOT TOUCH req, UNTIL IT COMPLETES! */
                goto out;
+       }
 
        zfcp_fsf_req_free(req);
        req = NULL;