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 */