Subject: Re: wd.c patch to reduce kernel stack usage
To: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
From: Jaromir Dolecek <jdolecek@netbsd.org>
List: tech-kern
Date: 06/27/2002 22:07:50
Would using
switch (retval) {
case ERROR:
{
char buf[256], *errbuf = &buf;
/* do error handling */
break;
}
suffice?
Jaromir
YAMAMOTO Takashi wrote:
> From: David Laight <david@l8s.co.uk>
> Subject: Re: wd.c patch to reduce kernel stack usage
> Date: Wed, 26 Jun 2002 21:51:33 +0100
>
> > > is attached patch ok?
> > > (in order to reduce kernel stack usage.)
> >
> > I'd be tempted to go the whole hog and make wdperror malloc()
> > a buffer that the caller has to free().
> >
> > That way the buffer cam be allocated by code that knows how big
> > it needs to be (and use snprint to ensure it isn't overrun.
>
> like this?
>
> ---
> YAMAMOTO Takashi<yamt@mwd.biglobe.ne.jp>
> Index: wd.c
> ===================================================================
> RCS file: /cvs/cvsroot/syssrc/sys/dev/ata/wd.c,v
> retrieving revision 1.220
> diff -u -p -r1.220 wd.c
> --- wd.c 2002/01/13 17:24:30 1.220
> +++ wd.c 2002/06/27 08:16:45
> @@ -181,7 +181,7 @@ void wdattach __P((struct device *, stru
> int wddetach __P((struct device *, int));
> int wdactivate __P((struct device *, enum devact));
> int wdprint __P((void *, char *));
> -void wdperror __P((struct ata_drive_datas *, int, char *));
> +char * wdperror __P((struct ata_drive_datas *, int));
>
> struct cfattach wd_ca = {
> sizeof(struct wd_softc), wdprobe, wdattach, wddetach, wdactivate
> @@ -589,14 +589,14 @@ wddone(v)
> {
> struct wd_softc *wd = v;
> struct buf *bp = wd->sc_bp;
> - char buf[256], *errbuf = buf;
> + char *buf = 0;
> + const char *errbuf;
> WDCDEBUG_PRINT(("wddone %s\n", wd->sc_dev.dv_xname),
> DEBUG_XFERS);
>
> if (bp == NULL)
> return;
> bp->b_resid = wd->sc_wdc_bio.bcount;
> - errbuf[0] = '\0';
> switch (wd->sc_wdc_bio.error) {
> case ERR_DMA:
> errbuf = "DMA error";
> @@ -612,11 +612,17 @@ wddone(v)
> if (wd->sc_wdc_bio.r_error != 0 &&
> (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
> goto noerror;
> - wdperror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf);
> + buf = wdperror(wd->drvp, wd->sc_wdc_bio.r_error);
> + if (buf)
> + errbuf = buf;
> + else
> + errbuf = ""; /* XXX */
> retry: /* Just reset and retry. Can we do more ? */
> wd->atabus->ata_reset_channel(wd->drvp);
> diskerr(bp, "wd", errbuf, LOG_PRINTF,
> wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
> + if (buf)
> + free((void *)buf, M_DEVBUF);
> if (wd->retries++ < WDIORETRIES) {
> printf(", retrying\n");
> callout_reset(&wd->sc_restart_ch, RECOVERYTIME,
> @@ -937,12 +943,14 @@ wdgetdisklabel(wd)
> #endif
> }
>
> -void
> -wdperror(drvp, errno, buf)
> +char *
> +wdperror(drvp, errno)
> struct ata_drive_datas *drvp;
> int errno;
> - char *buf;
> {
> +#define WD_MAX_ERROR_LEN 256
> + char *buf, *buf0;
> + size_t buflen;
> static char *errstr0_3[] = {"address mark not found",
> "track 0 not found", "aborted command", "media change requested",
> "id not found", "media changed", "uncorrectable data error",
> @@ -955,20 +963,41 @@ wdperror(drvp, errno, buf)
> int i;
> char *sep = "";
>
> + buflen = WD_MAX_ERROR_LEN;
> + buf = malloc(buflen, M_DEVBUF, M_NOWAIT);
> + if (buf == NULL)
> + return NULL;
> +
> if (drvp->ata_vers >= 4)
> errstr = errstr4_5;
> else
> errstr = errstr0_3;
>
> - if (errno == 0)
> - sprintf(buf, "error not notified");
> + if (errno == 0) {
> + if (snprintf(buf, buflen, "error not notified") < 0)
> + goto error;
> + return buf;
> + }
>
> + buf0 = buf;
> for (i = 0; i < 8; i++) {
> if (errno & (1 << i)) {
> - buf += sprintf(buf, "%s%s", sep, errstr[i]);
> + int ret;
> +
> + ret = snprintf(buf, buflen, "%s%s", sep, errstr[i]);
> + if (ret < 0) {
> +error:
> + free(buf0, M_DEVBUF);
> + return NULL;
> + }
> + if (ret >= buflen)
> + break;
> + buf += ret;
> + buflen -= ret;
> sep = ", ";
> }
> }
> + return buf0;
> }
>
> int
> @@ -1235,7 +1264,7 @@ wddump(dev, blkno, va, size)
> struct disklabel *lp; /* disk's disklabel */
> int part, err;
> int nblks; /* total number of sectors left to write */
> - char errbuf[256];
> + char *errbuf;
>
> /* Check if recursive dump; if so, punt. */
> if (wddoingadump)
> @@ -1313,8 +1342,13 @@ again:
> break;
> case ERROR:
> errbuf[0] = '\0';
> - wdperror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf);
> - printf("wddump: %s", errbuf);
> + errbuf = wdperror(wd->drvp, wd->sc_wdc_bio.r_error);
> + if (errbuf) {
> + printf("wddump: %s", errbuf);
> + free(errbuf, M_DEVBUF);
> + }
> + else
> + printf("wddump: error");
> err = EIO;
> break;
> case NOERROR:
--
Jaromir Dolecek <jdolecek@NetBSD.org> http://www.NetBSD.org/Ports/i386/ps2.html
-=- We should be mindful of the potential goal, but as the tantric -=-
-=- Buddhist masters say, ``You may notice during meditation that you -=-
-=- sometimes levitate or glow. Do not let this distract you.'' -=-