]> granicus.if.org Git - zfs/commitdiff
Add zpool_events_seek() functionality
authorBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 22 Nov 2013 22:52:16 +0000 (14:52 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 31 Mar 2014 23:10:57 +0000 (16:10 -0700)
The ZFS_IOC_EVENTS_SEEK ioctl was added to allow user space callers
to seek around the zevent file descriptor by EID.  When a specific
EID is passed and it exists the cursor will be positioned there.
If the EID is no longer cached by the kernel ENOENT is returned.
The caller may also pass ZEVENT_SEEK_START or ZEVENT_SEEK_END to seek
to those respective locations.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Chris Dunlap <cdunlap@llnl.gov>
Issue #2

include/libzfs.h
include/sys/fm/util.h
include/sys/fs/zfs.h
include/sys/zfs_ioctl.h
lib/libzfs/libzfs_pool.c
module/zfs/fm.c
module/zfs/zfs_ioctl.c

index 55dd34c99de18c96192c953c56a43f9000b7029b..cb78f1d6293126f7c3764672f4d1f9e2b0748ed1 100644 (file)
@@ -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 *);
index 9dfd436c1b43149aaf031f417163bc4404faf0cb..18fe490732394168403cd718a2e9d7ae354c66df 100644 (file)
@@ -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 *);
 
index 882e9e84ab85d220805900750ebcbc97e06221b9..ae72f834de523bb8c9839ee21d3d96071fbdfd2f 100644 (file)
@@ -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.
index dad611328cbcb43c206fb6d918000dc73e25715f..c63b16c78d321134844b147989bb97fa04ecde69 100644 (file)
@@ -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,
index b822ace688c950b5570c57a44a2c230e33f9db08..1b8f3b63a82a0822f8a037a0810fa57c03b40129 100644 (file)
@@ -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)
index fe9223ff81869cf3d85acf522cf088d9e9b76041..246b3d2cf606d01742c5bd989cd3f29024fda3ea 100644 (file)
@@ -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)
 {
index 5951bc673cb30be75c4070cf05ccaafee3733e66..cd47790166f559397f7ae7d698c7dcc6f719c95b 100644 (file)
@@ -4919,6 +4919,28 @@ zfs_ioc_events_clear(zfs_cmd_t *zc)
        return (0);
 }
 
+/*
+ * 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
@@ -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