aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libzfs.h1
-rw-r--r--include/sys/fm/util.h3
-rw-r--r--include/sys/fs/zfs.h1
-rw-r--r--include/sys/zfs_ioctl.h3
-rw-r--r--lib/libzfs/libzfs_pool.c36
-rw-r--r--module/zfs/fm.c61
-rw-r--r--module/zfs/zfs_ioctl.c24
7 files changed, 128 insertions, 1 deletions
diff --git a/include/libzfs.h b/include/libzfs.h
index 55dd34c99..cb78f1d62 100644
--- a/include/libzfs.h
+++ b/include/libzfs.h
@@ -410,6 +410,7 @@ extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
nvlist_t ***, uint_t *);
extern int zpool_events_next(libzfs_handle_t *, nvlist_t **, int *, int, int);
extern int zpool_events_clear(libzfs_handle_t *, int *);
+extern int zpool_events_seek(libzfs_handle_t *, uint64_t, int);
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t len);
extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
diff --git a/include/sys/fm/util.h b/include/sys/fm/util.h
index 9dfd436c1..18fe49073 100644
--- a/include/sys/fm/util.h
+++ b/include/sys/fm/util.h
@@ -71,7 +71,7 @@ typedef struct erpt_dump {
#ifdef _KERNEL
-#define ZEVENT_SHUTDOWN 0x1
+#define ZEVENT_SHUTDOWN 0x1
typedef void zevent_cb_t(nvlist_t *, nvlist_t *);
@@ -99,6 +99,7 @@ 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 *, uint64_t *);
extern int zfs_zevent_wait(zfs_zevent_t *);
+extern int zfs_zevent_seek(zfs_zevent_t *, uint64_t);
extern void zfs_zevent_init(zfs_zevent_t **);
extern void zfs_zevent_destroy(zfs_zevent_t *);
diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h
index 882e9e84a..ae72f834d 100644
--- a/include/sys/fs/zfs.h
+++ b/include/sys/fs/zfs.h
@@ -864,6 +864,7 @@ typedef enum zfs_ioc {
ZFS_IOC_LINUX = ('Z' << 8) + 0x80,
ZFS_IOC_EVENTS_NEXT,
ZFS_IOC_EVENTS_CLEAR,
+ ZFS_IOC_EVENTS_SEEK,
/*
* FreeBSD - 1/64 numbers reserved.
diff --git a/include/sys/zfs_ioctl.h b/include/sys/zfs_ioctl.h
index dad611328..c63b16c78 100644
--- a/include/sys/zfs_ioctl.h
+++ b/include/sys/zfs_ioctl.h
@@ -262,6 +262,9 @@ typedef struct zinject_record {
#define ZEVENT_NONBLOCK 0x1
#define ZEVENT_SIZE 1024
+#define ZEVENT_SEEK_START 0
+#define ZEVENT_SEEK_END UINT64_MAX
+
typedef enum zinject_type {
ZINJECT_UNINITIALIZED,
ZINJECT_DATA_FAULT,
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
index b822ace68..1b8f3b63a 100644
--- a/lib/libzfs/libzfs_pool.c
+++ b/lib/libzfs/libzfs_pool.c
@@ -3870,6 +3870,42 @@ zpool_events_clear(libzfs_handle_t *hdl, int *count)
return (0);
}
+/*
+ * Seek to a specific EID, ZEVENT_SEEK_START, or ZEVENT_SEEK_END for
+ * the passed zevent_fd file handle. On success zero is returned,
+ * otherwise -1 is returned and hdl->libzfs_error is set to the errno.
+ */
+int
+zpool_events_seek(libzfs_handle_t *hdl, uint64_t eid, int zevent_fd)
+{
+ zfs_cmd_t zc = {"\0"};
+ int error = 0;
+
+ zc.zc_guid = eid;
+ zc.zc_cleanup_fd = zevent_fd;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_EVENTS_SEEK, &zc) != 0) {
+ switch (errno) {
+ case ENOENT:
+ error = zfs_error_fmt(hdl, EZFS_NOENT,
+ dgettext(TEXT_DOMAIN, "cannot get event"));
+ break;
+
+ case ENOMEM:
+ error = zfs_error_fmt(hdl, EZFS_NOMEM,
+ dgettext(TEXT_DOMAIN, "cannot get event"));
+ break;
+
+ default:
+ error = zpool_standard_error_fmt(hdl, errno,
+ dgettext(TEXT_DOMAIN, "cannot get event"));
+ break;
+ }
+ }
+
+ return (error);
+}
+
void
zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
char *pathname, size_t len)
diff --git a/module/zfs/fm.c b/module/zfs/fm.c
index fe9223ff8..246b3d2cf 100644
--- a/module/zfs/fm.c
+++ b/module/zfs/fm.c
@@ -664,6 +664,67 @@ out:
return (error);
}
+/*
+ * The caller may seek to a specific EID by passing that EID. If the EID
+ * is still available in the posted list of events the cursor is positioned
+ * there. Otherwise ENOENT is returned and the cursor is not moved.
+ *
+ * There are two reserved EIDs which may be passed and will never fail.
+ * ZEVENT_SEEK_START positions the cursor at the start of the list, and
+ * ZEVENT_SEEK_END positions the cursor at the end of the list.
+ */
+int
+zfs_zevent_seek(zfs_zevent_t *ze, uint64_t eid)
+{
+ zevent_t *ev;
+ int error = 0;
+
+ mutex_enter(&zevent_lock);
+
+ if (eid == ZEVENT_SEEK_START) {
+ if (ze->ze_zevent)
+ list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
+ ze->ze_zevent = NULL;
+ goto out;
+ }
+
+ if (eid == ZEVENT_SEEK_END) {
+ if (ze->ze_zevent)
+ list_remove(&ze->ze_zevent->ev_ze_list, ze);
+
+ ev = list_head(&zevent_list);
+ if (ev) {
+ ze->ze_zevent = ev;
+ list_insert_head(&ev->ev_ze_list, ze);
+ } else {
+ ze->ze_zevent = NULL;
+ }
+
+ goto out;
+ }
+
+ for (ev = list_tail(&zevent_list); ev != NULL;
+ ev = list_prev(&zevent_list, ev)) {
+ if (ev->ev_eid == eid) {
+ 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);
+ break;
+ }
+ }
+
+ if (ev == NULL)
+ error = ENOENT;
+
+out:
+ mutex_exit(&zevent_lock);
+
+ return (error);
+}
+
void
zfs_zevent_init(zfs_zevent_t **zep)
{
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index 5951bc673..cd4779016 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -4921,6 +4921,28 @@ zfs_ioc_events_clear(zfs_cmd_t *zc)
/*
* inputs:
+ * zc_guid eid | ZEVENT_SEEK_START | ZEVENT_SEEK_END
+ * zc_cleanup zevent file descriptor
+ */
+static int
+zfs_ioc_events_seek(zfs_cmd_t *zc)
+{
+ zfs_zevent_t *ze;
+ minor_t minor;
+ int error;
+
+ error = zfs_zevent_fd_hold(zc->zc_cleanup_fd, &minor, &ze);
+ if (error != 0)
+ return (error);
+
+ error = zfs_zevent_seek(ze, zc->zc_guid);
+ zfs_zevent_fd_rele(zc->zc_cleanup_fd);
+
+ return (error);
+}
+
+/*
+ * inputs:
* zc_name name of new filesystem or snapshot
* zc_value full name of old snapshot
*
@@ -5393,6 +5415,8 @@ zfs_ioctl_init(void)
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
+ zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_SEEK, zfs_ioc_events_seek,
+ zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
}
int