summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2019-11-06 08:44:35 +0000
committerAndriy Gapon <avg@FreeBSD.org>2019-11-06 08:44:35 +0000
commit1838b83c8873a37123f99768b1b20f206f34ffdf (patch)
treef9bf2ceb0b07b14698060efd4166f1c8909cb977
parentccc8c172f78fa4bc4a79b54966aa92b14a0227a5 (diff)
Notes
-rw-r--r--cmd/zpool/zpool_main.c45
-rw-r--r--lib/libzfs/common/libzfs.h2
-rw-r--r--lib/libzfs/common/libzfs_pool.c21
-rw-r--r--lib/libzfs_core/common/libzfs_core.c34
-rw-r--r--lib/libzfs_core/common/libzfs_core.h3
-rw-r--r--man/man1m/zpool.1m16
-rw-r--r--uts/common/fs/zfs/zfs_ioctl.c43
-rw-r--r--uts/common/sys/fs/zfs.h1
8 files changed, 154 insertions, 11 deletions
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index 0c1c6483784c..8c384acc3b64 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -97,6 +97,8 @@ static int zpool_do_history(int, char **);
static int zpool_do_get(int, char **);
static int zpool_do_set(int, char **);
+static int zpool_do_sync(int, char **);
+
/*
* These libumem hooks provide a reasonable set of defaults for the allocator's
* debugging facilities.
@@ -141,6 +143,7 @@ typedef enum {
HELP_GET,
HELP_SET,
HELP_SPLIT,
+ HELP_SYNC,
HELP_REGUID,
HELP_REOPEN
} zpool_help_t;
@@ -197,6 +200,7 @@ static zpool_command_t command_table[] = {
{ "history", zpool_do_history, HELP_HISTORY },
{ "get", zpool_do_get, HELP_GET },
{ "set", zpool_do_set, HELP_SET },
+ { "sync", zpool_do_sync, HELP_SYNC },
};
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -283,6 +287,8 @@ get_usage(zpool_help_t idx)
"[<device> ...]\n"));
case HELP_REGUID:
return (gettext("\treguid <pool>\n"));
+ case HELP_SYNC:
+ return (gettext("\tsync [pool] ...\n"));
}
abort();
@@ -2616,6 +2622,45 @@ error:
return (err ? 1 : 0);
}
+/*
+ * zpool sync [-f] [pool] ...
+ *
+ * -f (undocumented) force uberblock (and config including zpool cache file)
+ * update.
+ *
+ * Sync the specified pool(s).
+ * Without arguments "zpool sync" will sync all pools.
+ * This command initiates TXG sync(s) and will return after the TXG(s) commit.
+ *
+ */
+static int
+zpool_do_sync(int argc, char **argv)
+{
+ int ret;
+ boolean_t force = B_FALSE;
+
+ /* check options */
+ while ((ret = getopt(argc, argv, "f")) != -1) {
+ switch (ret) {
+ case 'f':
+ force = B_TRUE;
+ break;
+ case '?':
+ (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+ optopt);
+ usage(B_FALSE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* if argc == 0 we will execute zpool_sync_one on all pools */
+ ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force);
+
+ return (ret);
+}
+
typedef struct iostat_cbdata {
boolean_t cb_verbose;
int cb_namewidth;
diff --git a/lib/libzfs/common/libzfs.h b/lib/libzfs/common/libzfs.h
index d296fed59f01..ce3ef0f8a851 100644
--- a/lib/libzfs/common/libzfs.h
+++ b/lib/libzfs/common/libzfs.h
@@ -269,6 +269,8 @@ extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
extern int zpool_reguid(zpool_handle_t *);
extern int zpool_reopen(zpool_handle_t *);
+extern int zpool_sync_one(zpool_handle_t *, void *);
+
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
vdev_state_t *);
extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);
diff --git a/lib/libzfs/common/libzfs_pool.c b/lib/libzfs/common/libzfs_pool.c
index b580772d5817..8504609b5ca2 100644
--- a/lib/libzfs/common/libzfs_pool.c
+++ b/lib/libzfs/common/libzfs_pool.c
@@ -3504,6 +3504,27 @@ zpool_reopen(zpool_handle_t *zhp)
return (zpool_standard_error(hdl, errno, msg));
}
+/* call into libzfs_core to execute the sync IOCTL per pool */
+int
+zpool_sync_one(zpool_handle_t *zhp, void *data)
+{
+ int ret;
+ libzfs_handle_t *hdl = zpool_get_handle(zhp);
+ const char *pool_name = zpool_get_name(zhp);
+ boolean_t *force = data;
+ nvlist_t *innvl = fnvlist_alloc();
+
+ fnvlist_add_boolean_value(innvl, "force", *force);
+ if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) {
+ nvlist_free(innvl);
+ return (zpool_standard_error_fmt(hdl, ret,
+ dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name));
+ }
+ nvlist_free(innvl);
+
+ return (0);
+}
+
/*
* Convert from a devid string to a path.
*/
diff --git a/lib/libzfs_core/common/libzfs_core.c b/lib/libzfs_core/common/libzfs_core.c
index 268f1d6a7a45..79e9901bd7e0 100644
--- a/lib/libzfs_core/common/libzfs_core.c
+++ b/lib/libzfs_core/common/libzfs_core.c
@@ -24,6 +24,7 @@
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Datto Inc.
*/
/*
@@ -128,17 +129,20 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
{
zfs_cmd_t zc = { 0 };
int error = 0;
- char *packed;
- size_t size;
+ char *packed = NULL;
+ size_t size = 0;
ASSERT3S(g_refcount, >, 0);
VERIFY3S(g_fd, !=, -1);
- (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+ if (name != NULL)
+ (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
- packed = fnvlist_pack(source, &size);
- zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
- zc.zc_nvlist_src_size = size;
+ if (source != NULL) {
+ packed = fnvlist_pack(source, &size);
+ zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+ zc.zc_nvlist_src_size = size;
+ }
if (resultp != NULL) {
*resultp = NULL;
@@ -416,6 +420,18 @@ lzc_exists(const char *dataset)
}
/*
+ * outnvl is unused.
+ * It was added to preserve the function signature in case it is
+ * needed in the future.
+ */
+/*ARGSUSED*/
+int
+lzc_sync(const char *pool_name, nvlist_t *innvl, nvlist_t **outnvl)
+{
+ return (lzc_ioctl(ZFS_IOC_POOL_SYNC, pool_name, innvl, NULL));
+}
+
+/*
* Create "user holds" on snapshots. If there is a hold on a snapshot,
* the snapshot can not be destroyed. (However, it can be marked for deletion
* by lzc_destroy_snaps(defer=B_TRUE).)
@@ -515,11 +531,7 @@ lzc_release(nvlist_t *holds, nvlist_t **errlist)
int
lzc_get_holds(const char *snapname, nvlist_t **holdsp)
{
- int error;
- nvlist_t *innvl = fnvlist_alloc();
- error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp);
- fnvlist_free(innvl);
- return (error);
+ return (lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, NULL, holdsp));
}
/*
diff --git a/lib/libzfs_core/common/libzfs_core.h b/lib/libzfs_core/common/libzfs_core.h
index 7dc618403e6e..cbc0c68af8fc 100644
--- a/lib/libzfs_core/common/libzfs_core.h
+++ b/lib/libzfs_core/common/libzfs_core.h
@@ -23,6 +23,7 @@
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Datto Inc.
*/
#ifndef _LIBZFS_CORE_H
@@ -91,6 +92,8 @@ boolean_t lzc_exists(const char *);
int lzc_rollback(const char *, char *, int);
int lzc_rollback_to(const char *, const char *);
+int lzc_sync(const char *, nvlist_t *, nvlist_t **);
+
int lzc_rename(const char *, const char *);
int lzc_destroy(const char *);
diff --git a/man/man1m/zpool.1m b/man/man1m/zpool.1m
index 2054e9491db6..80a8b3473e37 100644
--- a/man/man1m/zpool.1m
+++ b/man/man1m/zpool.1m
@@ -174,6 +174,9 @@
.Oo Ar pool Oc Ns ...
.Op Ar interval Op Ar count
.Nm
+.Cm sync
+.Oo Ar pool Oc Ns ...
+.Nm
.Cm upgrade
.Nm
.Cm upgrade
@@ -1782,6 +1785,19 @@ Warnings about pools not using the latest on-disk format will not be included.
.El
.It Xo
.Nm
+.Cm sync
+.Oo Ar pool Oc Ns ...
+.Xc
+Forces all in-core dirty data to be written to the primary pool storage and
+not the ZIL.
+It will also update administrative information including quota reporting.
+Without arguments,
+.Nm zpool Cm sync
+will sync all pools on the system.
+Otherwise, it will only sync the specified
+.Ar pool .
+.It Xo
+.Nm
.Cm upgrade
.Xc
Displays pools which do not have all supported features enabled and pools
diff --git a/uts/common/fs/zfs/zfs_ioctl.c b/uts/common/fs/zfs/zfs_ioctl.c
index a5d163481325..80c204e1824a 100644
--- a/uts/common/fs/zfs/zfs_ioctl.c
+++ b/uts/common/fs/zfs/zfs_ioctl.c
@@ -5522,6 +5522,7 @@ zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
static int
zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
{
+ ASSERT3P(args, ==, NULL);
return (dsl_dataset_get_holds(snapname, outnvl));
}
@@ -5790,6 +5791,44 @@ out:
return (error);
}
+/*
+ * Sync the currently open TXG to disk for the specified pool.
+ * This is somewhat similar to 'zfs_sync()'.
+ * For cases that do not result in error this ioctl will wait for
+ * the currently open TXG to commit before returning back to the caller.
+ *
+ * innvl: {
+ * "force" -> when true, force uberblock update even if there is no dirty data.
+ * In addition this will cause the vdev configuration to be written
+ * out including updating the zpool cache file. (boolean_t)
+ * }
+ *
+ * onvl is unused
+ */
+/* ARGSUSED */
+static int
+zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl)
+{
+ int err;
+ boolean_t force;
+ spa_t *spa;
+
+ if ((err = spa_open(pool, &spa, FTAG)) != 0)
+ return (err);
+
+ force = fnvlist_lookup_boolean_value(innvl, "force");
+ if (force) {
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_WRITER);
+ vdev_config_dirty(spa->spa_root_vdev);
+ spa_config_exit(spa, SCL_CONFIG, FTAG);
+ }
+ txg_wait_synced(spa_get_dsl(spa), 0);
+
+ spa_close(spa, FTAG);
+
+ return (err);
+}
+
static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST];
static void
@@ -5980,6 +6019,10 @@ zfs_ioctl_init(void)
zfs_ioc_pool_initialize, zfs_secpolicy_config, POOL_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+ zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC,
+ zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME,
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
+
/* IOCTLS that use the legacy function signature */
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
diff --git a/uts/common/sys/fs/zfs.h b/uts/common/sys/fs/zfs.h
index b0dbfe0f2537..0728f42212de 100644
--- a/uts/common/sys/fs/zfs.h
+++ b/uts/common/sys/fs/zfs.h
@@ -988,6 +988,7 @@ typedef enum zfs_ioc {
ZFS_IOC_POOL_CHECKPOINT,
ZFS_IOC_POOL_DISCARD_CHECKPOINT,
ZFS_IOC_POOL_INITIALIZE,
+ ZFS_IOC_POOL_SYNC,
ZFS_IOC_LAST
} zfs_ioc_t;