Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/ata wd(4): Fix bugs in softbadsect handling.
details: https://anonhg.NetBSD.org/src/rev/6b7cf27bb35f
branches: trunk
changeset: 1029239:6b7cf27bb35f
user: riastradh <riastradh%NetBSD.org@localhost>
date: Tue Dec 28 13:27:32 2021 +0000
description:
wd(4): Fix bugs in softbadsect handling.
- Don't copyout kernel virtual addresses (of SLIST entries) that
userland won't use anyway.
=> The structure still has space for this pointer; it's just always
null when userland gets it now.
- Don't copyout under a lock.
- Stop and return error if copyout fails (unless we've already copied
some out).
- Don't kmem_free under a lock.
XXX Unclear whether anyone actually uses WD_SOFTBADSECT or why --
it's always been disabled by default. Maybe we should just remove
it?
diffstat:
sys/dev/ata/wd.c | 51 +++++++++++++++++++++++++++++++++++++++++++--------
sys/dev/ata/wdvar.h | 18 ++++++++++++++++--
2 files changed, 59 insertions(+), 10 deletions(-)
diffs (166 lines):
diff -r 9af9d0361e3a -r 6b7cf27bb35f sys/dev/ata/wd.c
--- a/sys/dev/ata/wd.c Tue Dec 28 13:22:43 2021 +0000
+++ b/sys/dev/ata/wd.c Tue Dec 28 13:27:32 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wd.c,v 1.465 2020/09/28 12:47:49 jakllsch Exp $ */
+/* $NetBSD: wd.c,v 1.466 2021/12/28 13:27:32 riastradh 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.465 2020/09/28 12:47:49 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.466 2021/12/28 13:27:32 riastradh Exp $");
#include "opt_ata.h"
#include "opt_wd.h"
@@ -316,6 +316,7 @@
mutex_init(&wd->sc_lock, MUTEX_DEFAULT, IPL_BIO);
#ifdef WD_SOFTBADSECT
SLIST_INIT(&wd->sc_bslist);
+ cv_init(&wd->sc_bslist_cv, "wdbadsect");
#endif
wd->atabus = adev->adev_bustype;
wd->inflight = 0;
@@ -587,6 +588,11 @@
wd_sysctl_detach(wd);
+#ifdef WD_SOFTBADSECT
+ KASSERT(SLIST_EMPTY(&wd->sc_bslist));
+ cv_destroy(&wd->sc_bslist_cv);
+#endif
+
mutex_destroy(&wd->sc_lock);
wd->drvp->drive_type = ATA_DRIVET_NONE; /* no drive any more here */
@@ -1279,13 +1285,13 @@
return 0;
#endif
#ifdef WD_SOFTBADSECT
- case DIOCBSLIST :
- {
+ case DIOCBSLIST: {
uint32_t count, missing, skip;
struct disk_badsecinfo dbsi;
- struct disk_badsectors *dbs;
+ struct disk_badsectors *dbs, dbsbuf;
size_t available;
uint8_t *laddr;
+ int error;
dbsi = *(struct disk_badsecinfo *)addr;
missing = wd->sc_bscount;
@@ -1303,7 +1309,9 @@
* back to user space whilst the summary is returned via
* the struct passed in via the ioctl.
*/
+ error = 0;
mutex_enter(&wd->sc_lock);
+ wd->sc_bslist_inuse++;
SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next) {
if (skip > 0) {
missing--;
@@ -1313,30 +1321,57 @@
if (available < sizeof(*dbs))
break;
available -= sizeof(*dbs);
- copyout(dbs, laddr, sizeof(*dbs));
+ memset(&dbsbuf, 0, sizeof(dbsbuf));
+ dbsbuf.dbs_min = dbs->dbs_min;
+ dbsbuf.dbs_max = dbs->dbs_max;
+ dbsbuf.dbs_failedat = dbs->dbs_failedat;
+ mutex_exit(&wd->sc_lock);
+ error = copyout(&dbsbuf, laddr, sizeof(dbsbuf));
+ mutex_enter(&wd->sc_lock);
+ if (error)
+ break;
laddr += sizeof(*dbs);
missing--;
count++;
}
+ if (--wd->sc_bslist_inuse == 0)
+ cv_broadcast(&wd->sc_bslist_cv);
mutex_exit(&wd->sc_lock);
dbsi.dbsi_left = missing;
dbsi.dbsi_copied = count;
*(struct disk_badsecinfo *)addr = dbsi;
- return 0;
+
+ /*
+ * If we copied anything out, ignore error and return
+ * success -- can't back it out.
+ */
+ return count ? 0 : error;
}
- case DIOCBSFLUSH :
+ case DIOCBSFLUSH: {
+ int error;
+
/* Clean out the bad sector list */
mutex_enter(&wd->sc_lock);
+ while (wd->sc_bslist_inuse) {
+ error = cv_wait_sig(&wd->sc_bslist_cv, &wd->sc_lock);
+ if (error) {
+ mutex_exit(&wd->sc_lock);
+ return error;
+ }
+ }
while (!SLIST_EMPTY(&wd->sc_bslist)) {
struct disk_badsectors *dbs =
SLIST_FIRST(&wd->sc_bslist);
SLIST_REMOVE_HEAD(&wd->sc_bslist, dbs_next);
+ mutex_exit(&wd->sc_lock);
kmem_free(dbs, sizeof(*dbs));
+ mutex_enter(&wd->sc_lock);
}
mutex_exit(&wd->sc_lock);
wd->sc_bscount = 0;
return 0;
+ }
#endif
#ifdef notyet
diff -r 9af9d0361e3a -r 6b7cf27bb35f sys/dev/ata/wdvar.h
--- a/sys/dev/ata/wdvar.h Tue Dec 28 13:22:43 2021 +0000
+++ b/sys/dev/ata/wdvar.h Tue Dec 28 13:27:32 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: wdvar.h,v 1.50 2020/03/02 16:01:56 riastradh Exp $ */
+/* $NetBSD: wdvar.h,v 1.51 2021/12/28 13:27:32 riastradh Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -31,8 +31,20 @@
#include "opt_wd.h"
#endif
+#include <sys/types.h>
+
+#include <sys/callout.h>
+#include <sys/condvar.h>
+#include <sys/disk.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+
+#include <dev/ata/atareg.h>
+#include <dev/ata/atavar.h>
#include <dev/dkvar.h>
-#include <sys/sysctl.h>
+
+struct sysctllog;
struct wd_softc {
/* General disk infos */
@@ -64,6 +76,8 @@
#ifdef WD_SOFTBADSECT
SLIST_HEAD(, disk_badsectors) sc_bslist;
u_int sc_bscount;
+ kcondvar_t sc_bslist_cv;
+ u_int sc_bslist_inuse;
#endif
/* Retry/requeue failed transfers */
Home |
Main Index |
Thread Index |
Old Index