All of lore.kernel.org
 help / color / mirror / Atom feed
From: Elias Oltmanns <eo@nebensachen.de>
To: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Cc: linux-ide@vger.kernel.org
Subject: [PATCH] IDE: Fix HDIO_DRIVE_RESET handling
Date: Thu, 19 Jun 2008 01:35:01 +0200	[thread overview]
Message-ID: <87k5gmz596.fsf@denkblock.local> (raw)

Hi Bart,

currently, the code path executing an HDIO_DRIVE_RESET ioctl is broken
in various ways.  Firstly, ide_abort() is called with the ide_lock held
and may call ide_end_request() further down the line which will try to
grab the same lock again.  More importantly though, the whole concept of
aborting an inflight request is flawed -- at least as far as ide_abort()
is concerned.

The patch below tries to address these issues by handling the
HDIO_DRIVE_RESET ioctl in-band.  I wonder whether this approach is
acceptable and may be extended to other applications like a modified
version of the disk shock protection patches.  Also, I abstained from
using op codes 0x0 to 0x1f since at least part of this range is used by
ULDs like ide-floppy, ide-tape, etc.  On the other hand, there really
should be no conflict because those ULDs will always set ->rq_disk thus
preventing ide_special_rq() from snatching away what should be passed on
to ->do_request().  So, what's you're advice on this one?  Finally,
shouldn't op codes like REQ_DRIVE_RESET really be declared in a private
header file in drivers/ide/?

Signed-off-by: Elias Oltmanns <eo@nebensachen.de>
---

 drivers/ide/ide-io.c |   16 +++++++++++++++-
 drivers/ide/ide.c    |   40 ++++++++++++++--------------------------
 include/linux/ide.h  |    6 ++++++
 3 files changed, 35 insertions(+), 27 deletions(-)

diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 6965253..b3a37b1 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -788,6 +788,19 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
  	return ide_stopped;
 }
 
+static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
+{
+	switch (rq->cmd[0]) {
+	case REQ_DRIVE_RESET:
+		ide_end_request(drive, 1, 0);
+		return ide_do_reset(drive);
+	default:
+		blk_dump_rq_flags(rq, "ide_special_rq - bad request");
+		ide_end_request(drive, 0, 0);
+		return ide_stopped;
+	}
+}
+
 static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
 {
 	struct request_pm_state *pm = rq->data;
@@ -891,7 +904,8 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 			    pm->pm_step == ide_pm_state_completed)
 				ide_complete_pm_request(drive, rq);
 			return startstop;
-		}
+		} else if (!rq->rq_disk && blk_special_request(rq))
+			return ide_special_rq(drive, rq);
 
 		drv = *(ide_driver_t **)rq->rq_disk->private_data;
 		return drv->do_request(drive, rq, block);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index c758dcb..4f9c796 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -623,6 +623,19 @@ static int generic_ide_resume(struct device *dev)
 	return err;
 }
 
+static void generic_drive_reset(ide_drive_t *drive)
+{
+	struct request *rq;
+
+	rq = blk_get_request(drive->queue, 0, __GFP_WAIT);
+	/* Should we call ide_init_drive_cmd() here? */
+
+	rq->cmd[0] = REQ_DRIVE_RESET;
+	rq->cmd_type = REQ_TYPE_SPECIAL;
+	rq->cmd_flags |= REQ_SOFTBARRIER;
+	ide_do_drive_cmd(drive, rq, ide_end);
+}
+
 int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
 			unsigned int cmd, unsigned long arg)
 {
@@ -697,32 +710,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 
-			/*
-			 *	Abort the current command on the
-			 *	group if there is one, taking
-			 *	care not to allow anything else
-			 *	to be queued and to die on the
-			 *	spot if we miss one somehow
-			 */
-
-			spin_lock_irqsave(&ide_lock, flags);
-
-			if (HWGROUP(drive)->resetting) {
-				spin_unlock_irqrestore(&ide_lock, flags);
-				return -EBUSY;
-			}
-
-			ide_abort(drive, "drive reset");
-
-			BUG_ON(HWGROUP(drive)->handler);
-
-			/* Ensure nothing gets queued after we
-			   drop the lock. Reset will clear the busy */
-
-			HWGROUP(drive)->busy = 1;
-			spin_unlock_irqrestore(&ide_lock, flags);
-			(void) ide_do_reset(drive);
-
+			generic_drive_reset(drive);
 			return 0;
 		case HDIO_GET_BUSSTATE:
 			if (!capable(CAP_SYS_ADMIN))
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 9918772..4c3e802 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -842,6 +842,12 @@ int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 extern ide_startstop_t ide_do_reset (ide_drive_t *);
 
+/*
+ * Op codes for special requests to be handled by ide_special_rq().
+ * Values should be in the range of 0x20 to 0x3f.
+ */
+#define REQ_DRIVE_RESET		0x20
+
 extern void ide_init_drive_cmd (struct request *rq);
 
 /*

             reply	other threads:[~2008-06-18 23:35 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-18 23:35 Elias Oltmanns [this message]
2008-06-18 23:41 ` [PATCH] IDE: Fix HDIO_DRIVE_RESET handling Elias Oltmanns
2008-06-19 20:47 ` Bartlomiej Zolnierkiewicz
2008-06-22 23:23   ` Elias Oltmanns
2008-06-22 23:28     ` Elias Oltmanns
2008-06-23  7:47       ` Elias Oltmanns
2008-06-23 22:47         ` Bartlomiej Zolnierkiewicz
2008-06-23  9:16       ` Alan Cox
2008-06-24  7:02         ` Elias Oltmanns
2008-06-24  9:10           ` Alan Cox
2008-06-23 22:41       ` Bartlomiej Zolnierkiewicz
2008-06-24  7:12         ` Elias Oltmanns
2008-06-22 23:32     ` [PATCH 2/4] IDE: Remove unused code Elias Oltmanns
2008-06-22 23:35     ` [PATCH 3/4] Update documentation of HDIO_DRIVE_RESET ioctl Elias Oltmanns
2008-06-22 23:38     ` [PATCH 4/4] IDE: Report errors during drive reset back to user space Elias Oltmanns
2008-06-23  9:18     ` [PATCH] IDE: Fix HDIO_DRIVE_RESET handling Alan Cox
2008-06-23 22:41     ` Bartlomiej Zolnierkiewicz
2008-06-24  7:23       ` Elias Oltmanns
2008-06-24 11:06         ` Bartlomiej Zolnierkiewicz
2008-06-24 12:32           ` Alan Cox
2008-06-24 13:21             ` Bartlomiej Zolnierkiewicz
2008-06-24 13:35               ` Alan Cox
2008-06-24 14:19                 ` Bartlomiej Zolnierkiewicz
2008-06-24 14:33                   ` Bartlomiej Zolnierkiewicz
2008-06-25 11:23                   ` Elias Oltmanns
2008-06-25 11:27                     ` [PATCH 1/4 v2] " Elias Oltmanns
2008-06-25 11:28                     ` [PATCH 2/4 v2] IDE: Remove unused code Elias Oltmanns
2008-06-25 11:29                     ` [PATCH 3/4 v2] Update documentation of HDIO_DRIVE_RESET ioctl Elias Oltmanns
2008-06-25 11:30                     ` [PATCH 4/4 v2] IDE: Report errors during drive reset back to user space Elias Oltmanns
2008-06-25 20:24                     ` [PATCH] IDE: Fix HDIO_DRIVE_RESET handling Bartlomiej Zolnierkiewicz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87k5gmz596.fsf@denkblock.local \
    --to=eo@nebensachen.de \
    --cc=bzolnier@gmail.com \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.