|
From: | Paolo Bonzini |
Subject: | Re: [Qemu-devel] [PATCH v3 13/21] scsi: do not call send_command directly |
Date: | Fri, 20 May 2011 19:43:21 +0200 |
User-agent: | Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b3pre Mnenhy/0.8.3 Thunderbird/3.1.10 |
On 05/20/2011 06:04 PM, Christoph Hellwig wrote:
-void scsi_req_enqueue(SCSIRequest *req) +int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf) { + int32_t rc; assert(!req->enqueued); scsi_req_ref(req); req->enqueued = true; QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); + + /* Make sure the request doesn't disappear under send_command's feet. */ + scsi_req_ref(req); + rc = req->dev->info->send_command(req, buf); + scsi_req_unref(req); + return rc;How would it disappear given that we grabbed another reference just before?
Welcome to the wonderful world of nested callbacks. :(Suppose send_command completes a request. scsi_req_complete then dequeues it (which undoes the reference above), and calls the device who owned it. The device who owned the request then presumably NULLs a pointer and drops the last reference. The request is then freed.
This was exactly the kind of scenario that I was worried about when I thought about reference counting. I couldn't actually put my fingers on it, but I knew it was broken somewhere, and indeed a use-after-free was reported less than a month later.
It is not strictly necessary to wrap send_command with a ref/unref pair, but it is quite convenient when writing send_command. It also mirrors what I do around scsi_req_complete and scsi_req_cancel.
That probably needs a bit more documentation here. Also why not move the two scsi_req_ref calls together?
Because one is logically related to putting the request in the queue, while the other is related to the send_command op.
Paolo
[Prev in Thread] | Current Thread | [Next in Thread] |