diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2017-02-08 16:08:07 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2017-02-08 16:08:07 +0000 |
commit | a4d04d4c3b95eb335f51ce7f72b13190bd46c4a2 (patch) | |
tree | 35ddd40f853a72caa9799514c51d76c506a2bca4 /sys/dev/pv | |
parent | a66269d13b7befe043d47d07b54dd373d1270f62 (diff) |
Fixup incorrect test when allocating grant table entries
An xnf & xbf attach/detach loop has revealed that sometimes when we're
about to free a grant table entry that is still in use which is a grave
mistake code wise. Turned out we could allocate an entry twice because
of an incorrect test that took flags value into account when making the
decision regarding availability of a given entry. At the same time,
upon releasing the entry we explicitly CAS in 0 into the flags making
this check bogus.
While here be explicit about starting flags by initializing them to 0
and always panic when the "double free" condition is encountered.
rzalamena@ has lent me his eyes and has double-checked the condition.
Diffstat (limited to 'sys/dev/pv')
-rw-r--r-- | sys/dev/pv/xen.c | 16 |
1 files changed, 6 insertions, 10 deletions
diff --git a/sys/dev/pv/xen.c b/sys/dev/pv/xen.c index 244072c458e..1e93de05e83 100644 --- a/sys/dev/pv/xen.c +++ b/sys/dev/pv/xen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xen.c,v 1.76 2017/02/06 21:58:29 mikeb Exp $ */ +/* $OpenBSD: xen.c,v 1.77 2017/02/08 16:08:06 mikeb Exp $ */ /* * Copyright (c) 2015 Mike Belopuhov @@ -1039,11 +1039,11 @@ xen_grant_table_alloc(struct xen_softc *sc, grant_ref_t *ref) i = 0; if (ge->ge_reserved && i < ge->ge_reserved) continue; - if (ge->ge_table[i].flags != GTF_invalid && - ge->ge_table[i].frame != 0) + if (ge->ge_table[i].frame != 0) continue; *ref = ge->ge_start + i; /* XXX Mark as taken */ + ge->ge_table[i].flags = GTF_invalid; ge->ge_table[i].frame = 0xffffffff; if ((ge->ge_next = i + 1) == GNTTAB_NEPG) ge->ge_next = ge->ge_reserved; @@ -1080,13 +1080,9 @@ xen_grant_table_free(struct xen_softc *sc, grant_ref_t ref) ref -= ge->ge_start; if (ge->ge_table[ref].flags != GTF_invalid) { mtx_leave(&ge->ge_lock); -#ifdef XEN_DEBUG - panic("ref %u is still in use, sc %p gnt %p", ref + - ge->ge_start, sc, sc->sc_gnt); -#else - printf("%s: reference %u is still in use\n", - sc->sc_dev.dv_xname, ref + ge->ge_start); -#endif + panic("reference %u is still in use, flags %#x frame %#x", + ref + ge->ge_start, ge->ge_table[ref].flags, + ge->ge_table[ref].frame); } ge->ge_table[ref].frame = 0; ge->ge_next = ref; |