Add zpool_events_seek() functionality

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
This commit is contained in:
Brian Behlendorf 2013-11-22 14:52:16 -08:00
parent a2f1945ee3
commit 75e3ff58fe
7 changed files with 128 additions and 1 deletions

View File

@ -410,6 +410,7 @@ extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
nvlist_t ***, uint_t *); nvlist_t ***, uint_t *);
extern int zpool_events_next(libzfs_handle_t *, nvlist_t **, int *, int, int); 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_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 *, extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t len); size_t len);
extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *); extern int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);

View File

@ -71,7 +71,7 @@ typedef struct erpt_dump {
#ifdef _KERNEL #ifdef _KERNEL
#define ZEVENT_SHUTDOWN 0x1 #define ZEVENT_SHUTDOWN 0x1
typedef void zevent_cb_t(nvlist_t *, nvlist_t *); 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 void zfs_zevent_fd_rele(int);
extern int zfs_zevent_next(zfs_zevent_t *, nvlist_t **, uint64_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 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_init(zfs_zevent_t **);
extern void zfs_zevent_destroy(zfs_zevent_t *); extern void zfs_zevent_destroy(zfs_zevent_t *);

View File

@ -864,6 +864,7 @@ typedef enum zfs_ioc {
ZFS_IOC_LINUX = ('Z' << 8) + 0x80, ZFS_IOC_LINUX = ('Z' << 8) + 0x80,
ZFS_IOC_EVENTS_NEXT, ZFS_IOC_EVENTS_NEXT,
ZFS_IOC_EVENTS_CLEAR, ZFS_IOC_EVENTS_CLEAR,
ZFS_IOC_EVENTS_SEEK,
/* /*
* FreeBSD - 1/64 numbers reserved. * FreeBSD - 1/64 numbers reserved.

View File

@ -262,6 +262,9 @@ typedef struct zinject_record {
#define ZEVENT_NONBLOCK 0x1 #define ZEVENT_NONBLOCK 0x1
#define ZEVENT_SIZE 1024 #define ZEVENT_SIZE 1024
#define ZEVENT_SEEK_START 0
#define ZEVENT_SEEK_END UINT64_MAX
typedef enum zinject_type { typedef enum zinject_type {
ZINJECT_UNINITIALIZED, ZINJECT_UNINITIALIZED,
ZINJECT_DATA_FAULT, ZINJECT_DATA_FAULT,

View File

@ -3870,6 +3870,42 @@ zpool_events_clear(libzfs_handle_t *hdl, int *count)
return (0); 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 void
zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
char *pathname, size_t len) char *pathname, size_t len)

View File

@ -664,6 +664,67 @@ out:
return (error); 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 void
zfs_zevent_init(zfs_zevent_t **zep) zfs_zevent_init(zfs_zevent_t **zep)
{ {

View File

@ -4919,6 +4919,28 @@ zfs_ioc_events_clear(zfs_cmd_t *zc)
return (0); 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: * inputs:
* zc_name name of new filesystem or snapshot * 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_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear, zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE); 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 int