Page MenuHomeFreeBSD

D14533.id39792.diff
No OneTemporary

D14533.id39792.diff

Index: sys/geom/geom.h
===================================================================
--- sys/geom/geom.h
+++ sys/geom/geom.h
@@ -161,6 +161,8 @@
unsigned flags;
#define G_GEOM_WITHER 1
#define G_GEOM_VOLATILE_BIO 2
+#define G_GEOM_IN_ACCESS 4
+#define G_GEOM_ACCESS_WAIT 8
LIST_HEAD(,g_geom_alias) aliases;
};
Index: sys/geom/geom_subr.c
===================================================================
--- sys/geom/geom_subr.c
+++ sys/geom/geom_subr.c
@@ -876,7 +876,11 @@
g_access(struct g_consumer *cp, int dcr, int dcw, int dce)
{
struct g_provider *pp;
+ struct g_geom *gp;
int pw, pe;
+#ifdef INVARIANTS
+ int sr, sw, se;
+#endif
int error;
g_topology_assert();
@@ -904,6 +908,29 @@
return (ENXIO);
/*
+ * A number of GEOM classes either need to perform an I/O on the first
+ * open or to acquire a different subsystem's lock. To do that they
+ * may have to drop the topology lock.
+ * Other GEOM classes perform special actions when opening a lower rank
+ * geom for the first time. As a result, more than one thread may
+ * end up performing the special actions.
+ * So, we prevent concurrent "first" opens by marking the consumer with
+ * special flag.
+ *
+ * Note that if the geom's access method never drops the topology lock,
+ * then we will never see G_GEOM_IN_ACCESS here.
+ */
+ gp = pp->geom;
+ while ((gp->flags & G_GEOM_IN_ACCESS) != 0) {
+ g_trace(G_T_ACCESS,
+ "%s: race on geom %s via provider %s and consumer of %s",
+ __func__, gp->name, pp->name, cp->geom->name);
+ gp->flags |= G_GEOM_ACCESS_WAIT;
+ g_topology_sleep(gp, 0);
+ gp->flags &= ~G_GEOM_ACCESS_WAIT;
+ }
+
+ /*
* Figure out what counts the provider would have had, if this
* consumer had (r0w0e0) at this time.
*/
@@ -935,11 +962,25 @@
/* Ok then... */
- error = pp->geom->access(pp, dcr, dcw, dce);
+#ifdef INVARIANTS
+ sr = cp->acr;
+ sw = cp->acw;
+ se = cp->ace;
+#endif
+ gp->flags |= G_GEOM_IN_ACCESS;
+ error = gp->access(pp, dcr, dcw, dce);
KASSERT(dcr > 0 || dcw > 0 || dce > 0 || error == 0,
("Geom provider %s::%s dcr=%d dcw=%d dce=%d error=%d failed "
"closing ->access()", pp->geom->class->name, pp->name, dcr, dcw,
dce, error));
+
+ g_topology_assert();
+ gp->flags &= ~G_GEOM_IN_ACCESS;
+ KASSERT(cp->acr == sr && cp->acw == sw && cp->ace == se,
+ ("Access counts changed during geom->access"));
+ if ((gp->flags & G_GEOM_ACCESS_WAIT) != 0)
+ wakeup(gp);
+
if (!error) {
/*
* If we open first write, spoil any partner consumers.

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 16, 1:57 AM (7 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29731757
Default Alt Text
D14533.id39792.diff (2 KB)

Event Timeline