Skip to content

Commit

Permalink
OS-7058 need zfs trim support
Browse files Browse the repository at this point in the history
Requires SPL: 4692ce3f158ebf17707f4462b8a39e005be00a10

Porting notes:

VOP_SPACE's porting equivalent VNOP_IOCTL(F_PUNCHHOLE), was only added
at High Sierra - no hole support before then. But this is on pool file
vdevs, so it is mostly for debugging use.

Currently the unusual way to create kstats in spa_misc.c fails, and
is commented out.
  • Loading branch information
jjelinek authored and lundman committed Oct 23, 2018
1 parent 34c1df5 commit 242c765
Show file tree
Hide file tree
Showing 49 changed files with 2,814 additions and 221 deletions.
188 changes: 187 additions & 1 deletion cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* Copyright (c) 2012 by Frederik Wessels. All rights reserved.
* Copyright (c) 2012 by Cyril Plisko. All rights reserved.
* Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
* Copyright 2016 Nexenta Systems, Inc.
* Copyright 2017 Nexenta Systems, Inc.
* Copyright (c) 2017 Datto Inc.
*/

Expand Down Expand Up @@ -99,6 +99,7 @@ static int zpool_do_split(int, char **);

static int zpool_do_initialize(int, char **);
static int zpool_do_scrub(int, char **);
static int zpool_do_trim(int, char **);

static int zpool_do_import(int, char **);
static int zpool_do_export(int, char **);
Expand Down Expand Up @@ -150,6 +151,7 @@ typedef enum {
HELP_REMOVE,
HELP_INITIALIZE,
HELP_SCRUB,
HELP_TRIM,
HELP_STATUS,
HELP_UPGRADE,
HELP_EVENTS,
Expand Down Expand Up @@ -278,6 +280,8 @@ static zpool_command_t command_table[] = {
{ "initialize", zpool_do_initialize, HELP_INITIALIZE },
{ "scrub", zpool_do_scrub, HELP_SCRUB },
{ NULL },
{ "trim", zpool_do_trim, HELP_TRIM },
{ NULL },
{ "import", zpool_do_import, HELP_IMPORT },
{ "export", zpool_do_export, HELP_EXPORT },
{ "upgrade", zpool_do_upgrade, HELP_UPGRADE },
Expand Down Expand Up @@ -358,6 +362,8 @@ get_usage(zpool_help_t idx) {
return (gettext("\tinitialize [-cs] <pool> [<device> ...]\n"));
case HELP_SCRUB:
return (gettext("\tscrub [-s | -p] <pool> ...\n"));
case HELP_TRIM:
return (gettext("\ttrim [-s|-r <rate>] <pool> ...\n"));
case HELP_STATUS:
return (gettext("\tstatus [-gLPvxD] [-T d|u] [pool] ... "
"[interval [count]]\n"));
Expand Down Expand Up @@ -5728,6 +5734,31 @@ scrub_callback(zpool_handle_t *zhp, void *data)
return (err != 0);
}

typedef struct trim_cbdata {
boolean_t cb_start;
uint64_t cb_rate;
} trim_cbdata_t;

int
trim_callback(zpool_handle_t *zhp, void *data)
{
trim_cbdata_t *cb = data;
int err;

/*
* Ignore faulted pools.
*/
if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
(void) fprintf(stderr, gettext("cannot trim '%s': pool is "
"currently unavailable\n"), zpool_get_name(zhp));
return (1);
}

err = zpool_trim(zhp, cb->cb_start, cb->cb_rate);

return (err != 0);
}

/*
* zpool scrub [-s | -p] <pool> ...
*
Expand Down Expand Up @@ -5892,6 +5923,52 @@ zpool_do_initialize(int argc, char **argv)
return (err);
}

/*
* zpool trim [-s|-r <rate>] <pool> ...
*
* -s Stop. Stops any in-progress trim.
* -r <rate> Sets the TRIM rate.
*/
int
zpool_do_trim(int argc, char **argv)
{
int c;
trim_cbdata_t cb;

cb.cb_start = B_TRUE;
cb.cb_rate = 0;

/* check options */
while ((c = getopt(argc, argv, "sr:")) != -1) {
switch (c) {
case 's':
cb.cb_start = B_FALSE;
break;
case 'r':
if (zfs_nicestrtonum(NULL, optarg, &cb.cb_rate) == -1) {
(void) fprintf(stderr,
gettext("invalid value for rate\n"));
usage(B_FALSE);
}
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
}

argc -= optind;
argv += optind;

if (argc < 1) {
(void) fprintf(stderr, gettext("missing pool name argument\n"));
usage(B_FALSE);
}

return (for_each_pool(argc, argv, B_TRUE, NULL, trim_callback, &cb));
}

typedef struct status_cbdata {
int cb_count;
int cb_name_flags;
Expand Down Expand Up @@ -6224,6 +6301,59 @@ print_checkpoint_status(pool_checkpoint_stat_t *pcs)
space_buf);
}

static void
print_trim_status(uint64_t trim_prog, uint64_t total_size, uint64_t rate,
uint64_t start_time_u64, uint64_t end_time_u64)
{
time_t start_time = start_time_u64, end_time = end_time_u64;
char *buf;

assert(trim_prog <= total_size);
if (trim_prog != 0 && trim_prog != total_size) {
buf = ctime(&start_time);
buf[strlen(buf) - 1] = '\0'; /* strip trailing newline */
if (rate != 0) {
char rate_str[32];
zfs_nicenum(rate, rate_str, sizeof (rate_str));
(void) printf(" trim: %.02f%%\tstarted: %s\t"
"(rate: %s/s)\n", (((double)trim_prog) /
total_size) * 100, buf, rate_str);
} else {
(void) printf(" trim: %.02f%%\tstarted: %s\t"
"(rate: max)\n", (((double)trim_prog) /
total_size) * 100, buf);
}
} else {
if (start_time != 0) {
/*
* Non-zero start time means we were run at some point
* in the past.
*/
if (end_time != 0) {
/* Non-zero end time means we completed */
time_t diff = end_time - start_time;
int hrs, mins;

buf = ctime(&end_time);
buf[strlen(buf) - 1] = '\0';
hrs = diff / 3600;
mins = (diff % 3600) / 60;
(void) printf(gettext(" trim: completed on %s "
"(after %dh%dm)\n"), buf, hrs, mins);
} else {
buf = ctime(&start_time);
buf[strlen(buf) - 1] = '\0';
/* Zero end time means we were interrupted */
(void) printf(gettext(" trim: interrupted\t"
"(started %s)\n"), buf);
}
} else {
/* trim was never run */
(void) printf(gettext(" trim: none requested\n"));
}
}
}

static void
print_error_log(zpool_handle_t *zhp)
{
Expand Down Expand Up @@ -6335,6 +6465,43 @@ print_dedup_stats(nvlist_t *config)
zpool_dump_ddt(dds, ddh);
}

/*
* Calculates the total space available on log devices on the pool.
* For whatever reason, this is not counted in the root vdev's space stats.
*/
static uint64_t
zpool_slog_space(nvlist_t *nvroot)
{
nvlist_t **newchild;
uint_t c, children;
uint64_t space = 0;

verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
&newchild, &children) == 0);

for (c = 0; c < children; c++) {
uint64_t islog = B_FALSE;
vdev_stat_t *vs;
uint_t n;
uint_t n_subchildren = 1;
nvlist_t **subchild;

(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
&islog);
if (!islog)
continue;
verify(nvlist_lookup_uint64_array(newchild[c],
ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &n) == 0);

/* vdev can be non-leaf, so multiply by number of children */
(void) nvlist_lookup_nvlist_array(newchild[c],
ZPOOL_CONFIG_CHILDREN, &subchild, &n_subchildren);
space += n_subchildren * vs->vs_space;
}

return (space);
}

/*
* Display a summary of pool status. Displays a summary such as:
*
Expand Down Expand Up @@ -6638,6 +6805,7 @@ status_callback(zpool_handle_t *zhp, void *data)
pool_checkpoint_stat_t *pcs = NULL;
pool_scan_stat_t *ps = NULL;
pool_removal_stat_t *prs = NULL;
uint64_t trim_prog, trim_rate, trim_start_time, trim_stop_time;

(void) nvlist_lookup_uint64_array(nvroot,
ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
Expand All @@ -6651,6 +6819,24 @@ status_callback(zpool_handle_t *zhp, void *data)
print_removal_status(zhp, prs);
print_checkpoint_status(pcs);

/* Grab trim stats if the pool supports it */
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_PROG,
&trim_prog) == 0 &&
nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_RATE,
&trim_rate) == 0 &&
nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_START_TIME,
&trim_start_time) == 0 &&
nvlist_lookup_uint64(config, ZPOOL_CONFIG_TRIM_STOP_TIME,
&trim_stop_time) == 0) {
/*
* For whatever reason, root vdev_stats_t don't
* include log devices.
*/
print_trim_status(trim_prog, vs->vs_space +
zpool_slog_space(nvroot), trim_rate,
trim_start_time, trim_stop_time);
}

namewidth = max_width(zhp, nvroot, 0, 0, 0);
if (namewidth < 10)
namewidth = 10;
Expand Down
1 change: 1 addition & 0 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ typedef struct splitflags {
extern int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t);
extern int zpool_initialize(zpool_handle_t *, pool_initialize_func_t,
nvlist_t *);
extern int zpool_trim(zpool_handle_t *, boolean_t start, uint64_t rate);
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 *);
Expand Down
4 changes: 3 additions & 1 deletion include/sys/dmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2017 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright 2014 HybridCluster. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
Expand Down Expand Up @@ -370,6 +370,8 @@ typedef struct dmu_buf {
#define DMU_POOL_OBSOLETE_BPOBJ "com.delphix:obsolete_bpobj"
#define DMU_POOL_CONDENSING_INDIRECT "com.delphix:condensing_indirect"
#define DMU_POOL_ZPOOL_CHECKPOINT "com.delphix:zpool_checkpoint"
#define DMU_POOL_TRIM_START_TIME "trim_start_time"
#define DMU_POOL_TRIM_STOP_TIME "trim_stop_time"

/*
* Allocate an object from this objset. The range of object numbers
Expand Down
14 changes: 14 additions & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ typedef enum {
ZPOOL_PROP_TNAME,
ZPOOL_PROP_BOOTSIZE,
ZPOOL_PROP_CHECKPOINT,
ZPOOL_PROP_FORCETRIM,
ZPOOL_PROP_AUTOTRIM,
ZPOOL_NUM_PROPS
} zpool_prop_t;

Expand Down Expand Up @@ -697,6 +699,10 @@ typedef struct zpool_load_policy {
#define ZPOOL_CONFIG_REMOVED "removed"
#define ZPOOL_CONFIG_FRU "fru"
#define ZPOOL_CONFIG_AUX_STATE "aux_state"
#define ZPOOL_CONFIG_TRIM_PROG "trim_prog"
#define ZPOOL_CONFIG_TRIM_RATE "trim_rate"
#define ZPOOL_CONFIG_TRIM_START_TIME "trim_start_time"
#define ZPOOL_CONFIG_TRIM_STOP_TIME "trim_stop_time"

/* Pool load policy parameters */
#define ZPOOL_LOAD_POLICY "load-policy"
Expand Down Expand Up @@ -826,6 +832,14 @@ typedef enum pool_scan_func {
POOL_SCAN_FUNCS
} pool_scan_func_t;

/*
* TRIM command configuration info.
*/
typedef struct trim_cmd_info_s {
uint64_t tci_start; /* B_TRUE = start; B_FALSE = stop */
uint64_t tci_rate; /* requested TRIM rate in bytes/sec */
} trim_cmd_info_t;

/*
* Used to control scrub pause and resume.
*/
Expand Down
7 changes: 7 additions & 0 deletions include/sys/kstat_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ typedef struct osx_kstat {

kstat_named_t zfs_lua_max_instrlimit;
kstat_named_t zfs_lua_max_memlimit;

kstat_named_t zfs_trim;
kstat_named_t zfs_trim_min_ext_sz;

} osx_kstat_t;


Expand Down Expand Up @@ -232,6 +236,9 @@ extern uint64_t zfs_vdev_file_size_mismatch_cnt;
extern uint64_t zfs_lua_max_instrlimit;
extern uint64_t zfs_lua_max_memlimit;

extern uint64_t zfs_trim;
extern uint64_t zfs_trim_min_ext_sz;

int kstat_osx_init(void);
void kstat_osx_fini(void);

Expand Down
6 changes: 6 additions & 0 deletions include/sys/ldi_impl_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#define _SYS_LDI_IMPL_OSX_H

#include <sys/ldi_osx.h>
#include <sys/disk.h>
#include <sys/dkio.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -139,6 +141,8 @@ int ldi_open_media_by_dev(dev_t, int, ldi_handle_t *);
int ldi_open_media_by_path(char *, int, ldi_handle_t *);
int handle_get_bootinfo_iokit(struct ldi_handle *,
struct io_bootinfo *);
int handle_unmap_iokit(struct ldi_handle *,
dkioc_free_list_t *);

/* Handle vnode functions */
dev_t dev_from_path(char *);
Expand All @@ -159,6 +163,8 @@ int buf_strategy_vnode(ldi_buf_t *, struct ldi_handle *);
int ldi_open_vnode_by_path(char *, dev_t, int, ldi_handle_t *);
int handle_get_bootinfo_vnode(struct ldi_handle *,
struct io_bootinfo *);
int handle_unmap_vnode(struct ldi_handle *,
dkioc_free_list_t *);

/*
* LDI event information
Expand Down
Loading

0 comments on commit 242c765

Please sign in to comment.