Subject: Re: wd.c patch to reduce kernel stack usage
To: None <david@l8s.co.uk>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 06/27/2002 17:16:22
----Next_Part(Thu_Jun_27_17:16:22_2002_343)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
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>
----Next_Part(Thu_Jun_27_17:16:22_2002_343)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="wd.diff"
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:
----Next_Part(Thu_Jun_27_17:16:22_2002_343)----