diff options
author | Paul Dagnelie <[email protected]> | 2020-04-01 10:02:06 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-01 10:02:06 -0700 |
commit | 5a42ef04fd390dc96fbbf31bc9f3d05695998211 (patch) | |
tree | ee4aec968084618faa92988b08a3c41c9b904327 /lib | |
parent | c9e3efdb3a6111b9795becc6594b3c52ba004522 (diff) |
Add 'zfs wait' command
Add a mechanism to wait for delete queue to drain.
When doing redacted send/recv, many workflows involve deleting files
that contain sensitive data. Because of the way zfs handles file
deletions, snapshots taken quickly after a rm operation can sometimes
still contain the file in question, especially if the file is very
large. This can result in issues for redacted send/recv users who
expect the deleted files to be redacted in the send streams, and not
appear in their clones.
This change duplicates much of the zpool wait related logic into a
zfs wait command, which can be used to wait until the internal
deleteq has been drained. Additional wait activities may be added
in the future.
Reviewed-by: Matthew Ahrens <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: John Gallagher <[email protected]>
Signed-off-by: Paul Dagnelie <[email protected]>
Closes #9707
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libzfs/libzfs_dataset.c | 28 | ||||
-rw-r--r-- | lib/libzfs_core/libzfs_core.c | 20 |
2 files changed, 48 insertions, 0 deletions
diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 48d656323..45e7a79fb 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -5599,3 +5599,31 @@ zvol_volsize_to_reservation(zpool_handle_t *zph, uint64_t volsize, volsize += numdb; return (volsize); } + +/* + * Wait for the given activity and return the status of the wait (whether or not + * any waiting was done) in the 'waited' parameter. Non-existent fses are + * reported via the 'missing' parameter, rather than by printing an error + * message. This is convenient when this function is called in a loop over a + * long period of time (as it is, for example, by zfs's wait cmd). In that + * scenario, a fs being exported or destroyed should be considered a normal + * event, so we don't want to print an error when we find that the fs doesn't + * exist. + */ +int +zfs_wait_status(zfs_handle_t *zhp, zfs_wait_activity_t activity, + boolean_t *missing, boolean_t *waited) +{ + int error = lzc_wait_fs(zhp->zfs_name, activity, waited); + *missing = (error == ENOENT); + if (*missing) + return (0); + + if (error != 0) { + (void) zfs_standard_error_fmt(zhp->zfs_hdl, error, + dgettext(TEXT_DOMAIN, "error waiting in fs '%s'"), + zhp->zfs_name); + } + + return (error); +} diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index f65db4ff4..18143d364 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -1621,3 +1621,23 @@ lzc_wait_tag(const char *pool, zpool_wait_activity_t activity, uint64_t tag, { return (wait_common(pool, activity, B_TRUE, tag, waited)); } + +int +lzc_wait_fs(const char *fs, zfs_wait_activity_t activity, boolean_t *waited) +{ + nvlist_t *args = fnvlist_alloc(); + nvlist_t *result = NULL; + + fnvlist_add_int32(args, ZFS_WAIT_ACTIVITY, activity); + + int error = lzc_ioctl(ZFS_IOC_WAIT_FS, fs, args, &result); + + if (error == 0 && waited != NULL) + *waited = fnvlist_lookup_boolean_value(result, + ZFS_WAIT_WAITED); + + fnvlist_free(args); + fnvlist_free(result); + + return (error); +} |