Module Name: src
Committed By: jdolecek
Date: Sat Sep 22 17:50:09 UTC 2018
Modified Files:
src/sys/dev/ata [jdolecek-ncqfixes]: TODO.ncq ata_subr.c atavar.h wd.c
wdvar.h
Log Message:
remove explicit ata_channel_start() calls, it's no longer necessary
now that ata_xfer's are allocated via pool and not really limited;
replace by just a callout to restart the processing for rare cases
where system runs out of memory
To generate a diff of this commit:
cvs rdiff -u -r1.4.2.6 -r1.4.2.7 src/sys/dev/ata/TODO.ncq
cvs rdiff -u -r1.6.2.5 -r1.6.2.6 src/sys/dev/ata/ata_subr.c
cvs rdiff -u -r1.99.2.6 -r1.99.2.7 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.441.2.5 -r1.441.2.6 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.46.6.3 -r1.46.6.4 src/sys/dev/ata/wdvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ata/TODO.ncq
diff -u src/sys/dev/ata/TODO.ncq:1.4.2.6 src/sys/dev/ata/TODO.ncq:1.4.2.7
--- src/sys/dev/ata/TODO.ncq:1.4.2.6 Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/TODO.ncq Sat Sep 22 17:50:09 2018
@@ -1,6 +1,4 @@
jdolecek-ncqfixes goals:
-- add to wd(4) a callout to restart buf queue processing when ata_get_xfer()
- call fails and remove ata_channel_start()
- re-fix QEMU ahci(4) bug workaround (no READ LOG EXT support) - now it
triggers KASSERT()
- fix ahci(4) error handling under paralles - invalid bio via WD_CHAOS_MONKEY
Index: src/sys/dev/ata/ata_subr.c
diff -u src/sys/dev/ata/ata_subr.c:1.6.2.5 src/sys/dev/ata/ata_subr.c:1.6.2.6
--- src/sys/dev/ata/ata_subr.c:1.6.2.5 Sat Sep 22 09:22:59 2018
+++ src/sys/dev/ata/ata_subr.c Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $ */
+/* $NetBSD: ata_subr.c,v 1.6.2.6 2018/09/22 17:50:09 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -25,7 +25,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.6 2018/09/22 17:50:09 jdolecek Exp $");
#include "opt_ata.h"
@@ -257,54 +257,6 @@ ata_timeout(void *v)
splx(s);
}
-/*
- * Must be called without any locks, i.e. with both drive and channel locks
- * released.
- */
-void
-ata_channel_start(struct ata_channel *chp, int drive, bool start_self)
-{
- int i, s;
- struct ata_drive_datas *drvp;
-
- s = splbio();
-
- KASSERT(chp->ch_ndrives > 0);
-
-#define ATA_DRIVE_START(chp, drive) \
- do { \
- KASSERT(drive < chp->ch_ndrives); \
- drvp = &chp->ch_drive[drive]; \
- \
- if (drvp->drive_type != ATA_DRIVET_ATA && \
- drvp->drive_type != ATA_DRIVET_ATAPI && \
- drvp->drive_type != ATA_DRIVET_OLD) \
- continue; \
- \
- if (drvp->drv_start != NULL) \
- (*drvp->drv_start)(drvp->drv_softc); \
- } while (0)
-
- /*
- * Process drives in round robin fashion starting with next one after
- * the one which finished transfer. Thus no single drive would
- * completely starve other drives on same channel.
- * This loop processes all but the current drive, so won't do anything
- * if there is only one drive in channel.
- */
- for (i = (drive + 1) % chp->ch_ndrives; i != drive;
- i = (i + 1) % chp->ch_ndrives) {
- ATA_DRIVE_START(chp, i);
- }
-
- /* Now try to kick off xfers on the current drive */
- if (start_self)
- ATA_DRIVE_START(chp, drive);
-
- splx(s);
-#undef ATA_DRIVE_START
-}
-
void
ata_channel_lock(struct ata_channel *chp)
{
Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.99.2.6 src/sys/dev/ata/atavar.h:1.99.2.7
--- src/sys/dev/ata/atavar.h:1.99.2.6 Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/atavar.h Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: atavar.h,v 1.99.2.6 2018/09/22 16:14:25 jdolecek Exp $ */
+/* $NetBSD: atavar.h,v 1.99.2.7 2018/09/22 17:50:09 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -327,7 +327,6 @@ struct ata_drive_datas {
/* Callbacks into the drive's driver. */
void (*drv_done)(device_t, struct ata_xfer *); /* xfer is done */
- void (*drv_start)(device_t); /* start queue */
device_t drv_softc; /* ATA drives softc, if any */
struct ata_channel *chnl_softc; /* channel softc */
@@ -547,7 +546,6 @@ void ata_kill_active(struct ata_channel
void ata_reset_channel(struct ata_channel *, int);
void ata_channel_freeze(struct ata_channel *);
void ata_channel_thaw(struct ata_channel *);
-void ata_channel_start(struct ata_channel *, int, bool);
void ata_channel_lock(struct ata_channel *);
void ata_channel_unlock(struct ata_channel *);
void ata_channel_lock_owned(struct ata_channel *);
Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.441.2.5 src/sys/dev/ata/wd.c:1.441.2.6
--- src/sys/dev/ata/wd.c:1.441.2.5 Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/wd.c Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: wd.c,v 1.441.2.5 2018/09/22 16:14:25 jdolecek Exp $ */
+/* $NetBSD: wd.c,v 1.441.2.6 2018/09/22 17:50:09 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.5 2018/09/22 16:14:25 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.6 2018/09/22 17:50:09 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wd.h"
@@ -192,7 +192,7 @@ static void wi_free(struct wd_ioctl *);
static struct wd_ioctl *wi_get(struct wd_softc *);
static void wdioctlstrategy(struct buf *);
-static void wdstart(device_t);
+static void wdrestart(void *);
static void wdstart1(struct wd_softc *, struct buf *, struct ata_xfer *);
static int wd_diskstart(device_t, struct buf *);
static int wd_dumpblocks(device_t, void *, daddr_t, int);
@@ -324,7 +324,6 @@ wdattach(device_t parent, device_t self,
wd->drvp = adev->adev_drv_data;
wd->drvp->drv_openings = 1;
- wd->drvp->drv_start = wdstart;
wd->drvp->drv_done = wddone;
wd->drvp->drv_softc = dksc->sc_dev; /* done in atabusconfig_thread()
but too late */
@@ -333,6 +332,7 @@ wdattach(device_t parent, device_t self,
SLIST_INIT(&wd->sc_requeue_list);
callout_init(&wd->sc_retry_callout, 0); /* XXX MPSAFE */
callout_init(&wd->sc_requeue_callout, 0); /* XXX MPSAFE */
+ callout_init(&wd->sc_restart_diskqueue, 0); /* XXX MPSAFE */
aprint_naive("\n");
aprint_normal("\n");
@@ -527,6 +527,8 @@ wddetach(device_t self, int flags)
callout_destroy(&wd->sc_retry_callout);
callout_halt(&wd->sc_requeue_callout, &wd->sc_lock);
callout_destroy(&wd->sc_requeue_callout);
+ callout_halt(&wd->sc_restart_diskqueue, &wd->sc_lock);
+ callout_destroy(&wd->sc_restart_diskqueue);
mutex_exit(&wd->sc_lock);
@@ -749,6 +751,17 @@ wd_diskstart(device_t dev, struct buf *b
if (xfer == NULL) {
ATADEBUG_PRINT(("wd_diskstart %s no xfer\n",
dksc->sc_xname), DEBUG_XFERS);
+
+ /*
+ * No available memory, retry later. This happens very rarely
+ * and only under memory pressure, so wait relatively long
+ * before retry.
+ */
+ if (!callout_pending(&wd->sc_restart_diskqueue)) {
+ callout_reset(&wd->sc_restart_diskqueue, hz / 2,
+ wdrestart, dev);
+ }
+
mutex_exit(&wd->sc_lock);
return EAGAIN;
}
@@ -764,8 +777,9 @@ wd_diskstart(device_t dev, struct buf *b
* Queue a drive for I/O.
*/
static void
-wdstart(device_t self)
+wdrestart(void *x)
{
+ device_t self = x;
struct wd_softc *wd = device_private(self);
struct dk_softc *dksc = &wd->sc_dksc;
@@ -919,7 +933,6 @@ noerror: if ((xfer->c_bio.flags & ATA_CO
ata_free_xfer(wd->drvp->chnl_softc, xfer);
dk_done(dksc, bp);
- ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, true);
}
static void
@@ -1687,7 +1700,6 @@ wd_setcache(struct wd_softc *wd, int bit
out:
ata_free_xfer(wd->drvp->chnl_softc, xfer);
- ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, true);
return error;
}
@@ -1729,13 +1741,6 @@ wd_standby(struct wd_softc *wd, int flag
out:
ata_free_xfer(wd->drvp->chnl_softc, xfer);
-
- /*
- * Drive is supposed to go idle, start only other drives.
- * bufq might be actually already freed at this moment.
- */
- ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, false);
-
return error;
}
@@ -1792,10 +1797,6 @@ wd_flushcache(struct wd_softc *wd, int f
out_xfer:
ata_free_xfer(wd->drvp->chnl_softc, xfer);
-
- /* start again I/O processing possibly stopped due to no xfer */
- ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, start_self);
-
return error;
}
@@ -1855,7 +1856,6 @@ wd_trim(struct wd_softc *wd, daddr_t bno
out:
ata_free_xfer(wd->drvp->chnl_softc, xfer);
- ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, true);
return error;
}
@@ -2062,8 +2062,6 @@ wdioctlstrategy(struct buf *bp)
out:
ata_free_xfer(wi->wi_softc->drvp->chnl_softc, xfer);
- ata_channel_start(wi->wi_softc->drvp->chnl_softc,
- wi->wi_softc->drvp->drive, true);
out2:
bp->b_error = error;
if (error)
Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.46.6.3 src/sys/dev/ata/wdvar.h:1.46.6.4
--- src/sys/dev/ata/wdvar.h:1.46.6.3 Sat Sep 22 16:14:25 2018
+++ src/sys/dev/ata/wdvar.h Sat Sep 22 17:50:09 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: wdvar.h,v 1.46.6.3 2018/09/22 16:14:25 jdolecek Exp $ */
+/* $NetBSD: wdvar.h,v 1.46.6.4 2018/09/22 17:50:09 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -67,6 +67,7 @@ struct wd_softc {
/* Retry/requeue failed transfers */
SLIST_HEAD(, ata_xfer) sc_retry_list;
struct callout sc_retry_callout; /* retry callout handle */
+ struct callout sc_restart_diskqueue; /* restart queue processing */
SLIST_HEAD(, ata_xfer) sc_requeue_list;
struct callout sc_requeue_callout; /* requeue callout handle */