]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/scsi/sg.c
[SCSI] sg: avoid blk_put_request/blk_rq_unmap_user in interrupt
[karo-tx-linux.git] / drivers / scsi / sg.c
index 18d079e3990ea48063e1d61eb071c5ac6ba7c6b3..cdd83cf97100657a7672198a38b9671b3ac17019 100644 (file)
@@ -138,6 +138,7 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
        volatile char done;     /* 0->before bh, 1->before read, 2->read */
        struct request *rq;
        struct bio *bio;
+       struct execute_work ew;
 } Sg_request;
 
 typedef struct sg_fd {         /* holds the state of a file descriptor */
@@ -1234,6 +1235,15 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
+static void sg_rq_end_io_usercontext(struct work_struct *work)
+{
+       struct sg_request *srp = container_of(work, struct sg_request, ew.work);
+       struct sg_fd *sfp = srp->parentfp;
+
+       sg_finish_rem_req(srp);
+       kref_put(&sfp->f_ref, sg_remove_sfp);
+}
+
 /*
  * This function is a "bottom half" handler that is called by the mid
  * level when a command is completed (or has failed).
@@ -1312,10 +1322,9 @@ static void sg_rq_end_io(struct request *rq, int uptodate)
                 */
                wake_up_interruptible(&sfp->read_wait);
                kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
+               kref_put(&sfp->f_ref, sg_remove_sfp);
        } else
-               sg_finish_rem_req(srp); /* call with srp->done == 0 */
-
-       kref_put(&sfp->f_ref, sg_remove_sfp);
+               execute_in_process_context(sg_rq_end_io_usercontext, &srp->ew);
 }
 
 static struct file_operations sg_fops = {