summaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorBenjamin Block <bblock@linux.vnet.ibm.com>2017-08-23 19:57:56 -0400
committerJens Axboe <axboe@kernel.dk>2017-08-24 10:22:10 -0400
commit50b4d485528d1dbe0bd249f2073140e3444f4a7b (patch)
tree2060f67c0c03c8f87f37fe672c619389529c24a0 /block
parent1e6ec9ea89d30739b9447c1860fcb07fc29f3aef (diff)
bsg-lib: fix kernel panic resulting from missing allocation of reply-buffer
Since we split the scsi_request out of struct request bsg fails to provide a reply-buffer for the drivers. This was done via the pointer for sense-data, that is not preallocated anymore. Failing to allocate/assign it results in illegal dereferences because LLDs use this pointer unquestioned. An example panic on s390x, using the zFCP driver, looks like this (I had debugging on, otherwise NULL-pointer dereferences wouldn't even panic on s390x): Unable to handle kernel pointer dereference in virtual kernel address space Failing address: 6b6b6b6b6b6b6000 TEID: 6b6b6b6b6b6b6403 Fault in home space mode while using kernel ASCE. AS:0000000001590007 R3:0000000000000024 Oops: 0038 ilc:2 [#1] PREEMPT SMP DEBUG_PAGEALLOC Modules linked in: <Long List> CPU: 2 PID: 0 Comm: swapper/2 Not tainted 4.12.0-bsg-regression+ #3 Hardware name: IBM 2964 N96 702 (z/VM 6.4.0) task: 0000000065cb0100 task.stack: 0000000065cb4000 Krnl PSW : 0704e00180000000 000003ff801e4156 (zfcp_fc_ct_els_job_handler+0x16/0x58 [zfcp]) R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:2 PM:0 RI:0 EA:3 Krnl GPRS: 0000000000000001 000000005fa9d0d0 000000005fa9d078 0000000000e16866 000003ff00000290 6b6b6b6b6b6b6b6b 0000000059f78f00 000000000000000f 00000000593a0958 00000000593a0958 0000000060d88800 000000005ddd4c38 0000000058b50100 07000000659cba08 000003ff801e8556 00000000659cb9a8 Krnl Code: 000003ff801e4146: e31020500004 lg %r1,80(%r2) 000003ff801e414c: 58402040 l %r4,64(%r2) #000003ff801e4150: e35020200004 lg %r5,32(%r2) >000003ff801e4156: 50405004 st %r4,4(%r5) 000003ff801e415a: e54c50080000 mvhi 8(%r5),0 000003ff801e4160: e33010280012 lt %r3,40(%r1) 000003ff801e4166: a718fffb lhi %r1,-5 000003ff801e416a: 1803 lr %r0,%r3 Call Trace: ([<000003ff801e8556>] zfcp_fsf_req_complete+0x726/0x768 [zfcp]) [<000003ff801ea82a>] zfcp_fsf_reqid_check+0x102/0x180 [zfcp] [<000003ff801eb980>] zfcp_qdio_int_resp+0x230/0x278 [zfcp] [<00000000009b91b6>] qdio_kick_handler+0x2ae/0x2c8 [<00000000009b9e3e>] __tiqdio_inbound_processing+0x406/0xc10 [<00000000001684c2>] tasklet_action+0x15a/0x1d8 [<0000000000bd28ec>] __do_softirq+0x3ec/0x848 [<00000000001675a4>] irq_exit+0x74/0xf8 [<000000000010dd6a>] do_IRQ+0xba/0xf0 [<0000000000bd19e8>] io_int_handler+0x104/0x2d4 [<00000000001033b6>] enabled_wait+0xb6/0x188 ([<000000000010339e>] enabled_wait+0x9e/0x188) [<000000000010396a>] arch_cpu_idle+0x32/0x50 [<0000000000bd0112>] default_idle_call+0x52/0x68 [<00000000001cd0fa>] do_idle+0x102/0x188 [<00000000001cd41e>] cpu_startup_entry+0x3e/0x48 [<0000000000118c64>] smp_start_secondary+0x11c/0x130 [<0000000000bd2016>] restart_int_handler+0x62/0x78 [<0000000000000000>] (null) INFO: lockdep is turned off. Last Breaking-Event-Address: [<000003ff801e41d6>] zfcp_fc_ct_job_handler+0x3e/0x48 [zfcp] Kernel panic - not syncing: Fatal exception in interrupt This patch moves bsg-lib to allocate and setup struct bsg_job ahead of time, including the allocation of a buffer for the reply-data. This means, struct bsg_job is not allocated separately anymore, but as part of struct request allocation - similar to struct scsi_cmd. Reflect this in the function names that used to handle creation/destruction of struct bsg_job. Reported-by: Steffen Maier <maier@linux.vnet.ibm.com> Suggested-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Benjamin Block <bblock@linux.vnet.ibm.com> Fixes: 82ed4db499b8 ("block: split scsi_request out of struct request") Cc: <stable@vger.kernel.org> #4.11+ Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r--block/bsg-lib.c74
1 files changed, 44 insertions, 30 deletions
diff --git a/block/bsg-lib.c b/block/bsg-lib.c
index c4513b23f57a..dd56d7460cb9 100644
--- a/block/bsg-lib.c
+++ b/block/bsg-lib.c
@@ -29,26 +29,25 @@
29#include <scsi/scsi_cmnd.h> 29#include <scsi/scsi_cmnd.h>
30 30
31/** 31/**
32 * bsg_destroy_job - routine to teardown/delete a bsg job 32 * bsg_teardown_job - routine to teardown a bsg job
33 * @job: bsg_job that is to be torn down 33 * @job: bsg_job that is to be torn down
34 */ 34 */
35static void bsg_destroy_job(struct kref *kref) 35static void bsg_teardown_job(struct kref *kref)
36{ 36{
37 struct bsg_job *job = container_of(kref, struct bsg_job, kref); 37 struct bsg_job *job = container_of(kref, struct bsg_job, kref);
38 struct request *rq = job->req; 38 struct request *rq = job->req;
39 39
40 blk_end_request_all(rq, BLK_STS_OK);
41
42 put_device(job->dev); /* release reference for the request */ 40 put_device(job->dev); /* release reference for the request */
43 41
44 kfree(job->request_payload.sg_list); 42 kfree(job->request_payload.sg_list);
45 kfree(job->reply_payload.sg_list); 43 kfree(job->reply_payload.sg_list);
46 kfree(job); 44
45 blk_end_request_all(rq, BLK_STS_OK);
47} 46}
48 47
49void bsg_job_put(struct bsg_job *job) 48void bsg_job_put(struct bsg_job *job)
50{ 49{
51 kref_put(&job->kref, bsg_destroy_job); 50 kref_put(&job->kref, bsg_teardown_job);
52} 51}
53EXPORT_SYMBOL_GPL(bsg_job_put); 52EXPORT_SYMBOL_GPL(bsg_job_put);
54 53
@@ -100,7 +99,7 @@ EXPORT_SYMBOL_GPL(bsg_job_done);
100 */ 99 */
101static void bsg_softirq_done(struct request *rq) 100static void bsg_softirq_done(struct request *rq)
102{ 101{
103 struct bsg_job *job = rq->special; 102 struct bsg_job *job = blk_mq_rq_to_pdu(rq);
104 103
105 bsg_job_put(job); 104 bsg_job_put(job);
106} 105}
@@ -122,33 +121,20 @@ static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req)
122} 121}
123 122
124/** 123/**
125 * bsg_create_job - create the bsg_job structure for the bsg request 124 * bsg_prepare_job - create the bsg_job structure for the bsg request
126 * @dev: device that is being sent the bsg request 125 * @dev: device that is being sent the bsg request
127 * @req: BSG request that needs a job structure 126 * @req: BSG request that needs a job structure
128 */ 127 */
129static int bsg_create_job(struct device *dev, struct request *req) 128static int bsg_prepare_job(struct device *dev, struct request *req)
130{ 129{
131 struct request *rsp = req->next_rq; 130 struct request *rsp = req->next_rq;
132 struct request_queue *q = req->q;
133 struct scsi_request *rq = scsi_req(req); 131 struct scsi_request *rq = scsi_req(req);
134 struct bsg_job *job; 132 struct bsg_job *job = blk_mq_rq_to_pdu(req);
135 int ret; 133 int ret;
136 134
137 BUG_ON(req->special);
138
139 job = kzalloc(sizeof(struct bsg_job) + q->bsg_job_size, GFP_KERNEL);
140 if (!job)
141 return -ENOMEM;
142
143 req->special = job;
144 job->req = req;
145 if (q->bsg_job_size)
146 job->dd_data = (void *)&job[1];
147 job->request = rq->cmd; 135 job->request = rq->cmd;
148 job->request_len = rq->cmd_len; 136 job->request_len = rq->cmd_len;
149 job->reply = rq->sense; 137
150 job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer
151 * allocated */
152 if (req->bio) { 138 if (req->bio) {
153 ret = bsg_map_buffer(&job->request_payload, req); 139 ret = bsg_map_buffer(&job->request_payload, req);
154 if (ret) 140 if (ret)
@@ -187,7 +173,6 @@ static void bsg_request_fn(struct request_queue *q)
187{ 173{
188 struct device *dev = q->queuedata; 174 struct device *dev = q->queuedata;
189 struct request *req; 175 struct request *req;
190 struct bsg_job *job;
191 int ret; 176 int ret;
192 177
193 if (!get_device(dev)) 178 if (!get_device(dev))
@@ -199,7 +184,7 @@ static void bsg_request_fn(struct request_queue *q)
199 break; 184 break;
200 spin_unlock_irq(q->queue_lock); 185 spin_unlock_irq(q->queue_lock);
201 186
202 ret = bsg_create_job(dev, req); 187 ret = bsg_prepare_job(dev, req);
203 if (ret) { 188 if (ret) {
204 scsi_req(req)->result = ret; 189 scsi_req(req)->result = ret;
205 blk_end_request_all(req, BLK_STS_OK); 190 blk_end_request_all(req, BLK_STS_OK);
@@ -207,8 +192,7 @@ static void bsg_request_fn(struct request_queue *q)
207 continue; 192 continue;
208 } 193 }
209 194
210 job = req->special; 195 ret = q->bsg_job_fn(blk_mq_rq_to_pdu(req));
211 ret = q->bsg_job_fn(job);
212 spin_lock_irq(q->queue_lock); 196 spin_lock_irq(q->queue_lock);
213 if (ret) 197 if (ret)
214 break; 198 break;
@@ -219,6 +203,35 @@ static void bsg_request_fn(struct request_queue *q)
219 spin_lock_irq(q->queue_lock); 203 spin_lock_irq(q->queue_lock);
220} 204}
221 205
206static int bsg_init_rq(struct request_queue *q, struct request *req, gfp_t gfp)
207{
208 struct bsg_job *job = blk_mq_rq_to_pdu(req);
209 struct scsi_request *sreq = &job->sreq;
210
211 memset(job, 0, sizeof(*job));
212
213 scsi_req_init(sreq);
214 sreq->sense_len = SCSI_SENSE_BUFFERSIZE;
215 sreq->sense = kzalloc(sreq->sense_len, gfp);
216 if (!sreq->sense)
217 return -ENOMEM;
218
219 job->req = req;
220 job->reply = sreq->sense;
221 job->reply_len = sreq->sense_len;
222 job->dd_data = job + 1;
223
224 return 0;
225}
226
227static void bsg_exit_rq(struct request_queue *q, struct request *req)
228{
229 struct bsg_job *job = blk_mq_rq_to_pdu(req);
230 struct scsi_request *sreq = &job->sreq;
231
232 kfree(sreq->sense);
233}
234
222/** 235/**
223 * bsg_setup_queue - Create and add the bsg hooks so we can receive requests 236 * bsg_setup_queue - Create and add the bsg hooks so we can receive requests
224 * @dev: device to attach bsg device to 237 * @dev: device to attach bsg device to
@@ -235,7 +248,9 @@ struct request_queue *bsg_setup_queue(struct device *dev, char *name,
235 q = blk_alloc_queue(GFP_KERNEL); 248 q = blk_alloc_queue(GFP_KERNEL);
236 if (!q) 249 if (!q)
237 return ERR_PTR(-ENOMEM); 250 return ERR_PTR(-ENOMEM);
238 q->cmd_size = sizeof(struct scsi_request); 251 q->cmd_size = sizeof(struct bsg_job) + dd_job_size;
252 q->init_rq_fn = bsg_init_rq;
253 q->exit_rq_fn = bsg_exit_rq;
239 q->request_fn = bsg_request_fn; 254 q->request_fn = bsg_request_fn;
240 255
241 ret = blk_init_allocated_queue(q); 256 ret = blk_init_allocated_queue(q);
@@ -243,7 +258,6 @@ struct request_queue *bsg_setup_queue(struct device *dev, char *name,
243 goto out_cleanup_queue; 258 goto out_cleanup_queue;
244 259
245 q->queuedata = dev; 260 q->queuedata = dev;
246 q->bsg_job_size = dd_job_size;
247 q->bsg_job_fn = job_fn; 261 q->bsg_job_fn = job_fn;
248 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); 262 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
249 queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q); 263 queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q);