summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sys/fm/util.h2
-rw-r--r--module/zfs/fm.c21
-rw-r--r--module/zfs/zfs_ioctl.c5
3 files changed, 21 insertions, 7 deletions
diff --git a/include/sys/fm/util.h b/include/sys/fm/util.h
index 94947d67c..a3a8c3f86 100644
--- a/include/sys/fm/util.h
+++ b/include/sys/fm/util.h
@@ -96,7 +96,7 @@ extern void zfs_zevent_post(nvlist_t *, nvlist_t *, zevent_cb_t *);
extern void zfs_zevent_drain_all(int *);
extern int zfs_zevent_fd_hold(int, minor_t *, zfs_zevent_t **);
extern void zfs_zevent_fd_rele(int);
-extern int zfs_zevent_next(zfs_zevent_t *, nvlist_t **, uint64_t *);
+extern int zfs_zevent_next(zfs_zevent_t *, nvlist_t **, uint64_t *, uint64_t *);
extern int zfs_zevent_wait(zfs_zevent_t *);
extern void zfs_zevent_init(zfs_zevent_t **);
extern void zfs_zevent_destroy(zfs_zevent_t *);
diff --git a/module/zfs/fm.c b/module/zfs/fm.c
index 67d0c1a6e..d409b2974 100644
--- a/module/zfs/fm.c
+++ b/module/zfs/fm.c
@@ -568,13 +568,18 @@ zfs_zevent_fd_rele(int fd)
}
/*
- * Get the next zevent in the stream and place a copy in 'event'.
+ * Get the next zevent in the stream and place a copy in 'event'. This
+ * may fail with ENOMEM if the encoded nvlist size exceeds the passed
+ * 'event_size'. In this case the stream pointer is not advanced and
+ * and 'event_size' is set to the minimum required buffer size.
*/
int
-zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *dropped)
+zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *event_size,
+ uint64_t *dropped)
{
zevent_t *ev;
- int error;
+ size_t size;
+ int error = 0;
mutex_enter(&zevent_lock);
if (ze->ze_zevent == NULL) {
@@ -592,10 +597,18 @@ zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *dropped)
error = ENOENT;
goto out;
}
+ }
- list_remove(&ze->ze_zevent->ev_ze_list, ze);
+ VERIFY(nvlist_size(ev->ev_nvl, &size, NV_ENCODE_NATIVE) == 0);
+ if (size > *event_size) {
+ *event_size = size;
+ error = ENOMEM;
+ goto out;
}
+ if (ze->ze_zevent)
+ list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
ze->ze_zevent = ev;
list_insert_head(&ev->ev_ze_list, ze);
nvlist_dup(ev->ev_nvl, event, KM_SLEEP);
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index cc5e66f9a..45e118e53 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -4741,11 +4741,12 @@ zfs_ioc_events_next(zfs_cmd_t *zc)
return (error);
do {
- error = zfs_zevent_next(ze, &event, &dropped);
+ error = zfs_zevent_next(ze, &event,
+ &zc->zc_nvlist_dst_size, &dropped);
if (event != NULL) {
zc->zc_cookie = dropped;
error = put_nvlist(zc, event);
- nvlist_free(event);
+ nvlist_free(event);
}
if (zc->zc_guid & ZEVENT_NONBLOCK)