Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F147409260
D26140.id76139.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D26140.id76139.diff
View Options
Index: sys/kern/subr_bus.c
===================================================================
--- sys/kern/subr_bus.c
+++ sys/kern/subr_bus.c
@@ -392,9 +392,10 @@
.d_name = "devctl",
};
+#define DEVCTL_BUFFER (1024 - sizeof(void *))
struct dev_event_info {
- char *dei_data;
STAILQ_ENTRY(dev_event_info) dei_link;
+ char dei_data[DEVCTL_BUFFER];
};
STAILQ_HEAD(devq, dev_event_info);
@@ -409,8 +410,10 @@
struct selinfo sel;
struct devq devq;
struct sigio *sigio;
+ uma_zone_t zone;
} devsoftc;
+
static void filt_devctl_detach(struct knote *kn);
static int filt_devctl_read(struct knote *kn, long hint);
@@ -431,6 +434,11 @@
cv_init(&devsoftc.cv, "dev cv");
STAILQ_INIT(&devsoftc.devq);
knlist_init_mtx(&devsoftc.sel.si_note, &devsoftc.mtx);
+ if (devctl_queue_length > 0) {
+ devsoftc.zone = uma_zcreate("DEVCTL", sizeof(struct dev_event_info),
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ uma_prealloc(devsoftc.zone, devctl_queue_length);
+ }
devctl2_init();
}
@@ -495,8 +503,7 @@
devsoftc.queued--;
mtx_unlock(&devsoftc.mtx);
rv = uiomove(n1->dei_data, strlen(n1->dei_data), uio);
- free(n1->dei_data, M_BUS);
- free(n1, M_BUS);
+ uma_zfree(devsoftc.zone, n1);
return (rv);
}
@@ -585,42 +592,53 @@
return (devsoftc.inuse == 1);
}
-/**
- * @brief Queue data to be read from the devctl device
- *
- * Generic interface to queue data to the devctl device. It is
- * assumed that @p data is properly formatted. It is further assumed
- * that @p data is allocated using the M_BUS malloc type.
- */
-static void
-devctl_queue_data_f(char *data, int flags)
+static struct dev_event_info *
+devctl_alloc_dei()
{
- struct dev_event_info *n1 = NULL, *n2 = NULL;
+ struct dev_event_info *dei = NULL;
- if (strlen(data) == 0)
- goto out;
+ mtx_lock(&devsoftc.mtx);
if (devctl_queue_length == 0)
goto out;
- n1 = malloc(sizeof(*n1), M_BUS, flags);
- if (n1 == NULL)
- goto out;
- n1->dei_data = data;
- mtx_lock(&devsoftc.mtx);
- if (devctl_queue_length == 0) {
- mtx_unlock(&devsoftc.mtx);
- free(n1->dei_data, M_BUS);
- free(n1, M_BUS);
- return;
- }
- /* Leave at least one spot in the queue... */
- while (devsoftc.queued > devctl_queue_length - 1) {
- n2 = STAILQ_FIRST(&devsoftc.devq);
+ if (devctl_queue_length == devsoftc.queued) {
+ dei = STAILQ_FIRST(&devsoftc.devq);
STAILQ_REMOVE_HEAD(&devsoftc.devq, dei_link);
- free(n2->dei_data, M_BUS);
- free(n2, M_BUS);
devsoftc.queued--;
+ } else {
+ /* dei can't be NULL -- we know we have at least one in the zone */
+ dei = uma_zalloc(devsoftc.zone, M_NOWAIT);
+ MPASS(dei != NULL);
}
- STAILQ_INSERT_TAIL(&devsoftc.devq, n1, dei_link);
+ *dei->dei_data = '\0';
+out:
+ mtx_unlock(&devsoftc.mtx);
+ return (dei);
+}
+
+static struct dev_event_info *
+devctl_alloc_dei_sb(struct sbuf *sb)
+{
+ struct dev_event_info *dei;
+
+ dei = devctl_alloc_dei();
+ if (dei != NULL)
+ sbuf_new(sb, dei->dei_data, sizeof(dei->dei_data), SBUF_FIXEDLEN);
+ return (dei);
+}
+
+
+static void
+devctl_free_dei(struct dev_event_info *dei)
+{
+ uma_zfree(devsoftc.zone, dei);
+}
+
+static void
+devctl_queue(struct dev_event_info *dei)
+{
+// printf("%s", dei->dei_data);
+ mtx_lock(&devsoftc.mtx);
+ STAILQ_INSERT_TAIL(&devsoftc.devq, dei, dei_link);
devsoftc.queued++;
cv_broadcast(&devsoftc.cv);
KNOTE_LOCKED(&devsoftc.sel.si_note, 0);
@@ -628,20 +646,6 @@
selwakeup(&devsoftc.sel);
if (devsoftc.async && devsoftc.sigio != NULL)
pgsigio(&devsoftc.sigio, SIGIO, 0);
- return;
-out:
- /*
- * We have to free data on all error paths since the caller
- * assumes it will be free'd when this item is dequeued.
- */
- free(data, M_BUS);
- return;
-}
-
-static void
-devctl_queue_data(char *data)
-{
- devctl_queue_data_f(data, M_NOWAIT);
}
/**
@@ -649,34 +653,32 @@
*/
void
devctl_notify_f(const char *system, const char *subsystem, const char *type,
- const char *data, int flags)
-{
- int len = 0;
- char *msg;
-
- if (system == NULL)
- return; /* BOGUS! Must specify system. */
- if (subsystem == NULL)
- return; /* BOGUS! Must specify subsystem. */
- if (type == NULL)
- return; /* BOGUS! Must specify type. */
- len += strlen(" system=") + strlen(system);
- len += strlen(" subsystem=") + strlen(subsystem);
- len += strlen(" type=") + strlen(type);
- /* add in the data message plus newline. */
- if (data != NULL)
- len += strlen(data);
- len += 3; /* '!', '\n', and NUL */
- msg = malloc(len, M_BUS, flags);
- if (msg == NULL)
- return; /* Drop it on the floor */
- if (data != NULL)
- snprintf(msg, len, "!system=%s subsystem=%s type=%s %s\n",
- system, subsystem, type, data);
+ const char *data, int flags __unused)
+{
+ struct dev_event_info *dei;
+ struct sbuf sb;
+
+ if (system == NULL || subsystem == NULL || type == NULL)
+ return;
+ dei = devctl_alloc_dei_sb(&sb);
+ if (dei == NULL)
+ return;
+ sbuf_cpy(&sb, "!system=");
+ sbuf_cat(&sb, system);
+ sbuf_cat(&sb, " subsystem=");
+ sbuf_cat(&sb, subsystem);
+ sbuf_cat(&sb, " type=");
+ sbuf_cat(&sb, type);
+ if (data != NULL) {
+ sbuf_putc(&sb, ' ');
+ sbuf_cat(&sb, data);
+ }
+ sbuf_putc(&sb, '\n');
+ if (sbuf_finish(&sb) != 0)
+ devctl_free_dei(dei); /* overflow -> drop it */
else
- snprintf(msg, len, "!system=%s subsystem=%s type=%s\n",
- system, subsystem, type);
- devctl_queue_data_f(msg, flags);
+ devctl_queue(dei);
+ return;
}
void
@@ -698,54 +700,68 @@
* object of that event, plus the plug and play info and location info
* for that event. This is likely most useful for devices, but less
* useful for other consumers of this interface. Those should use
- * the devctl_queue_data() interface instead.
+ * the devctl_notify() interface instead.
+ *
+ * Output:
+ * ${type}${what} at $(location dev) $(pnp-info dev) on $(parent dev)
*/
+/* Note: we reach inside of sbuf because we may not be able to alloc here */
+#define SPACE(s) ((s)->s_size - (s)->s_len)
+#define EOB(s) ((s)->s_buf + (s)->s_len)
+
static void
devaddq(const char *type, const char *what, device_t dev)
{
- char *data = NULL;
- char *loc = NULL;
- char *pnp = NULL;
+ struct dev_event_info *dei;
const char *parstr;
+ char *p;
+ struct sbuf sb;
+ size_t space;
- if (!devctl_queue_length)/* Rare race, but lost races safely discard */
+ dei = devctl_alloc_dei_sb(&sb);
+ if (dei == NULL)
return;
- data = malloc(1024, M_BUS, M_NOWAIT);
- if (data == NULL)
- goto bad;
-
- /* get the bus specific location of this device */
- loc = malloc(1024, M_BUS, M_NOWAIT);
- if (loc == NULL)
+ sbuf_cpy(&sb, type);
+ sbuf_cat(&sb, what);
+ sbuf_cat(&sb, " at ");
+
+ /* Add in the location */
+ p = EOB(&sb);
+ *p = '\0'; /* sbuf buffer isn't NUL terminated until sbuf_finish() */
+ space = SPACE(&sb);
+ if (space <= 1)
goto bad;
- *loc = '\0';
- bus_child_location_str(dev, loc, 1024);
-
- /* Get the bus specific pnp info of this device */
- pnp = malloc(1024, M_BUS, M_NOWAIT);
- if (pnp == NULL)
+ bus_child_location_str(dev, p, space);
+ sbuf_setpos(&sb, sbuf_len(&sb) + strlen(p));
+ sbuf_putc(&sb, ' ');
+
+ /* Add in pnpinfo */
+ p = EOB(&sb);
+ *p = '\0';
+ space = SPACE(&sb);
+ if (space <= 1)
goto bad;
- *pnp = '\0';
- bus_child_pnpinfo_str(dev, pnp, 1024);
+ bus_child_pnpinfo_str(dev, p, space);
+ sbuf_setpos(&sb, sbuf_len(&sb) + strlen(p));
+ sbuf_cat(&sb, " on ");
/* Get the parent of this device, or / if high enough in the tree. */
if (device_get_parent(dev) == NULL)
parstr = "."; /* Or '/' ? */
else
parstr = device_get_nameunit(device_get_parent(dev));
- /* String it all together. */
- snprintf(data, 1024, "%s%s at %s %s on %s\n", type, what, loc, pnp,
- parstr);
- free(loc, M_BUS);
- free(pnp, M_BUS);
- devctl_queue_data(data);
+ sbuf_cat(&sb, parstr);
+ sbuf_putc(&sb, '\n');
+ if (sbuf_finish(&sb) != 0)
+ goto bad;
+ devctl_queue(dei);
return;
bad:
- free(pnp, M_BUS);
- free(loc, M_BUS);
- free(data, M_BUS);
+ devctl_free_dei(dei);
return;
}
+#undef SPACE
+#undef EOB
/*
* A device was added to the tree. We are called just after it successfully
@@ -786,7 +802,6 @@
static int
sysctl_devctl_queue(SYSCTL_HANDLER_ARGS)
{
- struct dev_event_info *n1;
int q, error;
q = devctl_queue_length;
@@ -795,18 +810,32 @@
return (error);
if (q < 0)
return (EINVAL);
- if (mtx_initialized(&devsoftc.mtx))
- mtx_lock(&devsoftc.mtx);
- devctl_queue_length = q;
- while (devsoftc.queued > devctl_queue_length) {
- n1 = STAILQ_FIRST(&devsoftc.devq);
- STAILQ_REMOVE_HEAD(&devsoftc.devq, dei_link);
- free(n1->dei_data, M_BUS);
- free(n1, M_BUS);
- devsoftc.queued--;
+
+ /*
+ * When set as a tunable, we've not yet initialized the mutex.
+ * It is safe to just assign to devctl_queue_length and return
+ * as we're racing no one. We'll use whatever value set in
+ * devinit.
+ */
+ if (!mtx_initialized(&devsoftc.mtx)) {
+ devctl_queue_length = q;
+ return (0);
}
- if (mtx_initialized(&devsoftc.mtx))
- mtx_unlock(&devsoftc.mtx);
+
+ /*
+ * XXX It's hard to grow or shrink the UMA zone. Only allow
+ * disabling the queue size for the moment until underlying
+ * UMA issues can be sorted out.
+ */
+ if (q != 0)
+ return (EINVAL);
+ if (q == devctl_queue_length)
+ return (0);
+ mtx_lock(&devsoftc.mtx);
+ devctl_queue_length = 0;
+ uma_zdestroy(devsoftc.zone);
+ devsoftc.zone = 0;
+ mtx_unlock(&devsoftc.mtx);
return (0);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 11, 6:19 PM (1 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29546398
Default Alt Text
D26140.id76139.diff (9 KB)
Attached To
Mode
D26140: devctl: move to using a uma zone
Attached
Detach File
Event Timeline
Log In to Comment