Skip to content

Commit be5efa7

Browse files
alek-plundman
authored andcommitted
Implemented zpool sync command
This addition will enable us to sync an open TXG to the main pool on demand. The functionality is similar to 'sync(2)' but 'zpool sync' will return when data has hit the main storage instead of potentially just the ZIL as is the case with the 'sync(2)' cmd. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Signed-off-by: Alek Pinchuk <apinchuk@datto.com>
1 parent 149f015 commit be5efa7

File tree

19 files changed

+681
-8
lines changed

19 files changed

+681
-8
lines changed

cmd/zpool/zpool_main.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
2828
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
2929
* Copyright 2016 Nexenta Systems, Inc.
30+
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
3031
* Copyright (c) 2017 Datto Inc.
3132
*/
3233

@@ -111,6 +112,8 @@ static int zpool_do_events(int, char **);
111112
static int zpool_do_get(int, char **);
112113
static int zpool_do_set(int, char **);
113114

115+
static int zpool_do_sync(int, char **);
116+
114117
/*
115118
* These libumem hooks provide a reasonable set of defaults for the allocator's
116119
* debugging facilities.
@@ -156,6 +159,7 @@ typedef enum {
156159
HELP_GET,
157160
HELP_SET,
158161
HELP_SPLIT,
162+
HELP_SYNC,
159163
HELP_REGUID,
160164
HELP_REOPEN
161165
} zpool_help_t;
@@ -288,6 +292,7 @@ static zpool_command_t command_table[] = {
288292
{ NULL },
289293
{ "get", zpool_do_get, HELP_GET },
290294
{ "set", zpool_do_set, HELP_SET },
295+
{ "sync", zpool_do_sync, HELP_SYNC },
291296
};
292297

293298
#define NCOMMAND (ARRAY_SIZE(command_table))
@@ -378,6 +383,8 @@ get_usage(zpool_help_t idx) {
378383
"[<device> ...]\n"));
379384
case HELP_REGUID:
380385
return (gettext("\treguid <pool>\n"));
386+
case HELP_SYNC:
387+
return (gettext("\tsync [pool] ...\n"));
381388
}
382389

383390
abort();
@@ -2966,6 +2973,45 @@ zpool_do_import(int argc, char **argv)
29662973
return (err ? 1 : 0);
29672974
}
29682975

2976+
/*
2977+
* zpool sync [-f] [pool] ...
2978+
*
2979+
* -f (undocumented) force uberblock (and config including zpool cache file)
2980+
* update.
2981+
*
2982+
* Sync the specified pool(s).
2983+
* Without arguments "zpool sync" will sync all pools.
2984+
* This command initiates TXG sync(s) and will return after the TXG(s) commit.
2985+
*
2986+
*/
2987+
static int
2988+
zpool_do_sync(int argc, char **argv)
2989+
{
2990+
int ret;
2991+
boolean_t force = B_FALSE;
2992+
2993+
/* check options */
2994+
while ((ret = getopt(argc, argv, "f")) != -1) {
2995+
switch (ret) {
2996+
case 'f':
2997+
force = B_TRUE;
2998+
break;
2999+
case '?':
3000+
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3001+
optopt);
3002+
usage(B_FALSE);
3003+
}
3004+
}
3005+
3006+
argc -= optind;
3007+
argv += optind;
3008+
3009+
/* if argc == 0 we will execute zpool_sync_one on all pools */
3010+
ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force);
3011+
3012+
return (ret);
3013+
}
3014+
29693015
typedef struct iostat_cbdata {
29703016
uint64_t cb_flags;
29713017
int cb_name_flags;

include/libzfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
295295
extern int zpool_reguid(zpool_handle_t *);
296296
extern int zpool_reopen(zpool_handle_t *);
297297

298+
extern int zpool_sync_one(zpool_handle_t *, void *);
299+
298300
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
299301
vdev_state_t *);
300302
extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);

include/libzfs_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ int lzc_channel_program_nosync(const char *, const char *, uint64_t,
114114
int lzc_sync(const char *, nvlist_t *, nvlist_t **);
115115
int lzc_reopen(const char *, boolean_t);
116116

117+
int lzc_sync(const char *, nvlist_t *, nvlist_t **);
118+
117119
#ifdef __cplusplus
118120
}
119121
#endif

include/sys/zfs_ioctl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,8 @@ typedef enum zfs_ioc {
591591
ZFS_IOC_POOL_INITIALIZE,
592592

593593
ZFS_IOC_CHANNEL_PROGRAM,
594+
ZFS_IOC_POOL_SYNC,
595+
594596
/*
595597
* Linux - 3/64 numbers reserved.
596598
*/

lib/libzfs/libzfs_pool.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3679,6 +3679,27 @@ zpool_reopen(zpool_handle_t *zhp)
36793679
return (zpool_standard_error(hdl, errno, msg));
36803680
}
36813681

3682+
/* call into libzfs_core to execute the sync IOCTL per pool */
3683+
int
3684+
zpool_sync_one(zpool_handle_t *zhp, void *data)
3685+
{
3686+
int ret;
3687+
libzfs_handle_t *hdl = zpool_get_handle(zhp);
3688+
const char *pool_name = zpool_get_name(zhp);
3689+
boolean_t *force = data;
3690+
nvlist_t *innvl = fnvlist_alloc();
3691+
3692+
fnvlist_add_boolean_value(innvl, "force", *force);
3693+
if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) {
3694+
nvlist_free(innvl);
3695+
return (zpool_standard_error_fmt(hdl, ret,
3696+
dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name));
3697+
}
3698+
nvlist_free(innvl);
3699+
3700+
return (0);
3701+
}
3702+
36823703
/*
36833704
* Convert from a devid string to a path.
36843705
*/

lib/libzfs_core/libzfs_core.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* Copyright (c) 2013 Steven Hartland. All rights reserved.
2525
* Copyright (c) 2014 Integros [integros.com]
2626
* Copyright 2017 RackTop Systems.
27+
* Copyright (c) 2017 Datto Inc.
2728
*/
2829

2930
/*
@@ -135,7 +136,8 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
135136
ASSERT3S(g_refcount, >, 0);
136137
VERIFY3S(g_fd, !=, -1);
137138

138-
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
139+
if (name != NULL)
140+
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
139141

140142
if (source != NULL) {
141143
packed = fnvlist_pack(source, &size);
@@ -410,6 +412,18 @@ lzc_exists(const char *dataset)
410412
return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
411413
}
412414

415+
/*
416+
* outnvl is unused.
417+
* It was added to preserve the function signature in case it is
418+
* needed in the future.
419+
*/
420+
/*ARGSUSED*/
421+
int
422+
lzc_sync(const char *pool_name, nvlist_t *innvl, nvlist_t **outnvl)
423+
{
424+
return (lzc_ioctl(ZFS_IOC_POOL_SYNC, pool_name, innvl, NULL));
425+
}
426+
413427
/*
414428
* Create "user holds" on snapshots. If there is a hold on a snapshot,
415429
* the snapshot can not be destroyed. (However, it can be marked for deletion
@@ -510,11 +524,7 @@ lzc_release(nvlist_t *holds, nvlist_t **errlist)
510524
int
511525
lzc_get_holds(const char *snapname, nvlist_t **holdsp)
512526
{
513-
int error;
514-
nvlist_t *innvl = fnvlist_alloc();
515-
error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp);
516-
fnvlist_free(innvl);
517-
return (error);
527+
return (lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, NULL, holdsp));
518528
}
519529

520530
/*

man/man8/zpool.8

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@
173173
.Oo Ar pool Oc Ns ...
174174
.Op Ar interval Op Ar count
175175
.Nm
176+
.Cm sync
177+
.Oo Ar pool Oc Ns ...
178+
.Nm
176179
.Cm upgrade
177180
.Nm
178181
.Cm upgrade
@@ -1803,6 +1806,18 @@ Warnings about pools not using the latest on-disk format will not be included.
18031806
.El
18041807
.It Xo
18051808
.Nm
1809+
.Cm sync
1810+
.Oo Ar pool Oc Ns ...
1811+
.Xc
1812+
This command forces all in-core dirty data to be written to the primary pool
1813+
storage and not the ZIL.
1814+
It will also update administrative information including quota reporting.
1815+
Without arguments,
1816+
.Sx zpool sync
1817+
will sync all pools on the system.
1818+
Otherwise, it will sync only the specified pool(s).
1819+
.It Xo
1820+
.Nm
18061821
.Cm upgrade
18071822
.Xc
18081823
Displays pools which do not have all supported features enabled and pools

module/zfs/zfs_ioctl.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
* Copyright (c) 2014 Integros [integros.com]
3737
* Copyright 2016 Toomas Soome <tsoome@me.com>
3838
* Copyright 2017 RackTop Systems.
39-
* Copyright (c) 2017 Datto Inc.
39+
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
40+
* Copyright (c) 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
4041
*/
4142

4243
#define __APPLE_API_PRIVATE
@@ -5315,6 +5316,7 @@ zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
53155316
static int
53165317
zfs_ioc_get_holds(const char *snapname, nvlist_t *args, nvlist_t *outnvl)
53175318
{
5319+
ASSERT3P(args, ==, NULL);
53185320
return (dsl_dataset_get_holds(snapname, outnvl));
53195321
}
53205322

@@ -5843,6 +5845,43 @@ zfs_ioc_osx_proxy_dataset(zfs_cmd_t *zc)
58435845
return (error);
58445846
}
58455847

5848+
/*
5849+
* Sync the currently open TXG to disk for the specified pool.
5850+
* This is somewhat similar to 'zfs_sync()'.
5851+
* For cases that do not result in error this ioctl will wait for
5852+
* the currently open TXG to commit before returning back to the caller.
5853+
*
5854+
* innvl: {
5855+
* "force" -> when true, force uberblock update even if there is no dirty data.
5856+
* In addition this will cause the vdev configuration to be written
5857+
* out including updating the zpool cache file. (boolean_t)
5858+
* }
5859+
*
5860+
* onvl is unused
5861+
*/
5862+
/* ARGSUSED */
5863+
static int
5864+
zfs_ioc_pool_sync(const char *pool, nvlist_t *innvl, nvlist_t *onvl)
5865+
{
5866+
int err;
5867+
boolean_t force;
5868+
spa_t *spa;
5869+
5870+
if ((err = spa_open(pool, &spa, FTAG)) != 0)
5871+
return (err);
5872+
5873+
force = fnvlist_lookup_boolean_value(innvl, "force");
5874+
if (force) {
5875+
spa_config_enter(spa, SCL_CONFIG, FTAG, RW_WRITER);
5876+
vdev_config_dirty(spa->spa_root_vdev);
5877+
spa_config_exit(spa, SCL_CONFIG, FTAG);
5878+
}
5879+
txg_wait_synced(spa_get_dsl(spa), 0);
5880+
5881+
spa_close(spa, FTAG);
5882+
5883+
return (err);
5884+
}
58465885

58475886
static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST];
58485887

@@ -6045,6 +6084,10 @@ zfs_ioctl_init(void)
60456084
POOL_NAME, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE,
60466085
B_TRUE);
60476086

6087+
zfs_ioctl_register("sync", ZFS_IOC_POOL_SYNC,
6088+
zfs_ioc_pool_sync, zfs_secpolicy_none, POOL_NAME,
6089+
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE);
6090+
60486091
/* IOCTLS that use the legacy function signature */
60496092

60506093
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,

tests/runfiles/linux.run

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ tests = ['zpool_upgrade_001_pos',
391391
'zpool_upgrade_006_neg', 'zpool_upgrade_008_pos',
392392
'zpool_upgrade_009_neg']
393393

394+
[tests/functional/cli_root/zpool_sync]
395+
tests = ['zpool_sync_001_pos', 'zpool_sync_002_neg']
396+
394397
# DISABLED:
395398
# zfs_share_001_neg - requires additional dependencies
396399
# zfs_unshare_001_neg - requires additional dependencies

tests/zfs-tests/include/libtest.shlib

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
# Use is subject to license terms.
2525
# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
2626
# Copyright 2016 Nexenta Systems, Inc.
27+
# Copyright (c) 2017 Lawrence Livermore National Security, LLC.
2728
# Copyright (c) 2017 Datto Inc.
2829
#
2930

@@ -3274,6 +3275,46 @@ function format_zvol # volume_name blockdev mountpoint
32743275
fi
32753276
}
32763277

3278+
#
3279+
# Sync data to the pool
3280+
#
3281+
# $1 pool name
3282+
# $2 boolean to force uberblock (and config including zpool cache file) update
3283+
#
3284+
function sync_pool #pool <force>
3285+
{
3286+
typeset pool=${1:-$TESTPOOL}
3287+
typeset force=${2:-false}
3288+
3289+
if [[ $force == true ]]; then
3290+
log_must zpool sync -f $pool
3291+
else
3292+
log_must zpool sync $pool
3293+
fi
3294+
3295+
return 0
3296+
}
3297+
3298+
#
3299+
# Sync data to the pool
3300+
#
3301+
# $1 pool name
3302+
# $2 boolean to force uberblock (and config including zpool cache file) update
3303+
#
3304+
function sync_pool #pool <force>
3305+
{
3306+
typeset pool=${1:-$TESTPOOL}
3307+
typeset force=${2:-false}
3308+
3309+
if [[ $force == true ]]; then
3310+
log_must zpool sync -f $pool
3311+
else
3312+
log_must zpool sync $pool
3313+
fi
3314+
3315+
return 0
3316+
}
3317+
32773318
function unmount_fs_mountpoint # mountpoint
32783319
{
32793320
typeset mountpoint=$1

0 commit comments

Comments
 (0)