From patchwork Mon Oct 17 15:37:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 120250 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 077DCB6F9C for ; Tue, 18 Oct 2011 02:38:25 +1100 (EST) Received: from localhost ([::1]:33568 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RFpGg-0007bV-6W for incoming@patchwork.ozlabs.org; Mon, 17 Oct 2011 11:38:22 -0400 Received: from eggs.gnu.org ([140.186.70.92]:35854) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RFpGa-0007ax-CO for qemu-devel@nongnu.org; Mon, 17 Oct 2011 11:38:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RFpGZ-0000Wa-3h for qemu-devel@nongnu.org; Mon, 17 Oct 2011 11:38:16 -0400 Received: from mail-qy0-f173.google.com ([209.85.216.173]:55822) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RFpGZ-0000WV-0p for qemu-devel@nongnu.org; Mon, 17 Oct 2011 11:38:15 -0400 Received: by qyk10 with SMTP id 10so1410590qyk.4 for ; Mon, 17 Oct 2011 08:38:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=xoOFYWcKaZsvUXplXY9QQdHdFktOxaonFcnWZkP+THI=; b=GyACacqJAe2GYSvvDW4NJgb16UyWHFd08vEeUqg9GYJClYtCr8YDs/B+QXdZKci8Xs WjRWqssfPokHJHJytrDxAdDZPirjiVp8QZakMPvh5FAhOmMP/WSCg3o6KVcevEwkJ3zv rnC7M79kW/tFBBqivvfZo+MFc9Uoy66l1u3/U= Received: by 10.68.26.69 with SMTP id j5mr38770201pbg.110.1318865894351; Mon, 17 Oct 2011 08:38:14 -0700 (PDT) Received: from localhost.localdomain (93-34-218-143.ip51.fastwebnet.it. [93.34.218.143]) by mx.google.com with ESMTPS id h5sm59892289pbq.11.2011.10.17.08.38.10 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 17 Oct 2011 08:38:12 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Mon, 17 Oct 2011 17:37:47 +0200 Message-Id: <1318865867-2785-1-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1318503845-11473-22-git-send-email-pbonzini@redhat.com> References: <1318503845-11473-22-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.216.173 Cc: kwolf@redhat.com Subject: [Qemu-devel] [PATCH v2 21/35] scsi-disk: bump SCSIRequest reference count until aio completion runs X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org In some cases a request may be canceled before the completion callback runs. Keep a reference to the request between starting an AIO operation, and let scsi_*_complete remove it. Since scsi_handle_rw_error returns whether something else has to be done for the request by the caller, it makes sense to transfer ownership of the ref to scsi_handle_rw_error when it returns 1; scsi_dma_restart_bh will then free the reference after restarting the operation. Signed-off-by: Paolo Bonzini --- v1->v2: Add "return" after calling scsi_write_complete with ENOMEDIUM. Bump refcount before testing data direction. hw/scsi-disk.c | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index e28c39d..702e6ca 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -139,6 +139,7 @@ static void scsi_read_complete(void * opaque, int ret) if (ret) { if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) { + /* Leave in ref for scsi_dma_restart_bh. */ return; } } @@ -149,6 +150,7 @@ static void scsi_read_complete(void * opaque, int ret) r->sector += n; r->sector_count -= n; scsi_req_data(&r->req, r->qiov.size); + scsi_req_unref(&r->req); } static void scsi_flush_complete(void * opaque, int ret) @@ -163,11 +165,13 @@ static void scsi_flush_complete(void * opaque, int ret) if (ret < 0) { if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) { + /* Leave in ref for scsi_dma_restart_bh. */ return; } } scsi_req_complete(&r->req, GOOD); + scsi_req_unref(&r->req); } /* Read more data from scsi device into buffer. */ @@ -193,6 +197,8 @@ static void scsi_read_data(SCSIRequest *req) /* No data transfer may already be in progress */ assert(r->req.aiocb == NULL); + /* Save a ref for scsi_read_complete, in case r is canceled. */ + scsi_req_ref(&r->req); if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { DPRINTF("Data transfer direction invalid\n"); scsi_read_complete(r, -EINVAL); @@ -201,7 +207,9 @@ static void scsi_read_data(SCSIRequest *req) if (s->tray_open) { scsi_read_complete(r, -ENOMEDIUM); + return; } + n = scsi_init_iovec(r); bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n, @@ -279,6 +287,7 @@ static void scsi_write_complete(void * opaque, int ret) DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size); scsi_req_data(&r->req, r->qiov.size); } + scsi_req_unref(&r->req); } static void scsi_write_data(SCSIRequest *req) @@ -290,6 +299,8 @@ static void scsi_write_data(SCSIRequest *req) /* No data transfer may already be in progress */ assert(r->req.aiocb == NULL); + /* Save a ref for scsi_write_complete, in case r is canceled. */ + scsi_req_ref(&r->req); if (r->req.cmd.mode != SCSI_XFER_TO_DEV) { DPRINTF("Data transfer direction invalid\n"); scsi_write_complete(r, -EINVAL); @@ -300,6 +311,7 @@ static void scsi_write_data(SCSIRequest *req) if (n) { if (s->tray_open) { scsi_write_complete(r, -ENOMEDIUM); + return; } bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE); r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, @@ -344,6 +356,8 @@ static void scsi_dma_restart_bh(void *opaque) scsi_req_complete(&r->req, GOOD); } } + /* This reference was left in by scsi_handle_rw_error. */ + scsi_req_unref(&r->req); } } } @@ -1345,6 +1359,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) r->iov.iov_len = rc; break; case SYNCHRONIZE_CACHE: + /* Save a ref for scsi_flush_complete, in case r is canceled. */ + scsi_req_ref(&r->req); bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH); r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r); if (r->req.aiocb == NULL) {