Skip to content

Commit df71897

Browse files
committed
Add TXG timestamp database
This feature enables tracking of when TXGs are committed to disk, providing an estimated timestamp for each TXG. With this information, it becomes possible to perform scrubs based on specific date ranges, improving the granularity of data management and recovery operations. Signed-off-by: Mariusz Zaborski <[email protected]> Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc.
1 parent a6f2025 commit df71897

File tree

18 files changed

+645
-11
lines changed

18 files changed

+645
-11
lines changed

cmd/zpool/zpool_main.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ get_usage(zpool_help_t idx)
513513
return (gettext("\tinitialize [-c | -s | -u] [-w] <pool> "
514514
"[<device> ...]\n"));
515515
case HELP_SCRUB:
516-
return (gettext("\tscrub [-e | -s | -p | -C] [-w] "
516+
return (gettext("\tscrub [-e | -s | -p | -C | -E | -S] [-w] "
517517
"<pool> ...\n"));
518518
case HELP_RESILVER:
519519
return (gettext("\tresilver <pool> ...\n"));
@@ -8368,6 +8368,8 @@ zpool_do_reopen(int argc, char **argv)
83688368
typedef struct scrub_cbdata {
83698369
int cb_type;
83708370
pool_scrub_cmd_t cb_scrub_cmd;
8371+
time_t cb_date_start;
8372+
time_t cb_date_end;
83718373
} scrub_cbdata_t;
83728374

83738375
static boolean_t
@@ -8411,7 +8413,8 @@ scrub_callback(zpool_handle_t *zhp, void *data)
84118413
return (1);
84128414
}
84138415

8414-
err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
8416+
err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd, cb->cb_date_start,
8417+
cb->cb_date_end);
84158418

84168419
if (err == 0 && zpool_has_checkpoint(zhp) &&
84178420
cb->cb_type == POOL_SCAN_SCRUB) {
@@ -8430,10 +8433,27 @@ wait_callback(zpool_handle_t *zhp, void *data)
84308433
return (zpool_wait(zhp, *act));
84318434
}
84328435

8436+
static time_t
8437+
date_string_to_sec(const char *timestr)
8438+
{
8439+
struct tm tm = {0};
8440+
8441+
if (strptime(timestr, "%Y-%m-%d %H:%M", &tm) == NULL) {
8442+
if (strptime(timestr, "%Y-%m-%d", &tm) == NULL) {
8443+
fprintf(stderr, gettext("Failed to parse the date.\n"));
8444+
usage(B_FALSE);
8445+
}
8446+
}
8447+
8448+
return (timegm(&tm));
8449+
}
8450+
84338451
/*
8434-
* zpool scrub [-e | -s | -p | -C] [-w] <pool> ...
8452+
* zpool scrub [-e | -s | -p | -C | -E | -S] [-w] <pool> ...
84358453
*
84368454
* -e Only scrub blocks in the error log.
8455+
* -E End date of scrub.
8456+
* -S Start date of scrub.
84378457
* -s Stop. Stops any in-progress scrub.
84388458
* -p Pause. Pause in-progress scrub.
84398459
* -w Wait. Blocks until scrub has completed.
@@ -8449,21 +8469,28 @@ zpool_do_scrub(int argc, char **argv)
84498469

84508470
cb.cb_type = POOL_SCAN_SCRUB;
84518471
cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
8472+
cb.cb_date_start = cb.cb_date_end = 0;
84528473

84538474
boolean_t is_error_scrub = B_FALSE;
84548475
boolean_t is_pause = B_FALSE;
84558476
boolean_t is_stop = B_FALSE;
84568477
boolean_t is_txg_continue = B_FALSE;
84578478

84588479
/* check options */
8459-
while ((c = getopt(argc, argv, "spweC")) != -1) {
8480+
while ((c = getopt(argc, argv, "spweCE:S:")) != -1) {
84608481
switch (c) {
84618482
case 'e':
84628483
is_error_scrub = B_TRUE;
84638484
break;
8485+
case 'E':
8486+
cb.cb_date_end = date_string_to_sec(optarg);
8487+
break;
84648488
case 's':
84658489
is_stop = B_TRUE;
84668490
break;
8491+
case 'S':
8492+
cb.cb_date_start = date_string_to_sec(optarg);
8493+
break;
84678494
case 'p':
84688495
is_pause = B_TRUE;
84698496
break;
@@ -8511,6 +8538,19 @@ zpool_do_scrub(int argc, char **argv)
85118538
}
85128539
}
85138540

8541+
if ((cb.cb_date_start != 0 || cb.cb_date_end != 0) &&
8542+
cb.cb_scrub_cmd != POOL_SCRUB_NORMAL) {
8543+
(void) fprintf(stderr, gettext("invalid option combination: "
8544+
"start/end date is available only with normal scrub\n"));
8545+
usage(B_FALSE);
8546+
}
8547+
if (cb.cb_date_start != 0 && cb.cb_date_end != 0 &&
8548+
cb.cb_date_start > cb.cb_date_end) {
8549+
(void) fprintf(stderr, gettext("invalid arguments: "
8550+
"end date has to be later than start date\n"));
8551+
usage(B_FALSE);
8552+
}
8553+
85148554
if (wait && (cb.cb_type == POOL_SCAN_NONE ||
85158555
cb.cb_scrub_cmd == POOL_SCRUB_PAUSE)) {
85168556
(void) fprintf(stderr, gettext("invalid option combination: "
@@ -8551,6 +8591,7 @@ zpool_do_resilver(int argc, char **argv)
85518591

85528592
cb.cb_type = POOL_SCAN_RESILVER;
85538593
cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
8594+
cb.cb_date_start = cb.cb_date_end = 0;
85548595

85558596
/* check options */
85568597
while ((c = getopt(argc, argv, "")) != -1) {

include/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ COMMON_H = \
1010
cityhash.h \
1111
zfeature_common.h \
1212
zfs_comutil.h \
13+
zfs_crrd.h \
1314
zfs_deleg.h \
1415
zfs_fletcher.h \
1516
zfs_namecheck.h \

include/libzfs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ typedef struct trimflags {
291291
/*
292292
* Functions to manipulate pool and vdev state
293293
*/
294-
_LIBZFS_H int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t);
294+
_LIBZFS_H int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t,
295+
time_t, time_t);
295296
_LIBZFS_H int zpool_initialize(zpool_handle_t *, pool_initialize_func_t,
296297
nvlist_t *);
297298
_LIBZFS_H int zpool_initialize_wait(zpool_handle_t *, pool_initialize_func_t,

include/sys/dmu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ typedef struct dmu_buf {
394394
#define DMU_POOL_ZPOOL_CHECKPOINT "com.delphix:zpool_checkpoint"
395395
#define DMU_POOL_LOG_SPACEMAP_ZAP "com.delphix:log_spacemap_zap"
396396
#define DMU_POOL_DELETED_CLONES "com.delphix:deleted_clones"
397+
#define DMU_POOL_TXG_LOG_TIME_MINUTES "com.klaraystems:txg_log_time:minutes"
398+
#define DMU_POOL_TXG_LOG_TIME_DAYS "com.klaraystems:txg_log_time:days"
399+
#define DMU_POOL_TXG_LOG_TIME_MONTHS "com.klaraystems:txg_log_time:months"
397400

398401
/*
399402
* Allocate an object from this objset. The range of object numbers

include/sys/spa_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
#include <sys/dsl_deadlist.h>
5656
#include <zfeature_common.h>
5757

58+
#include "zfs_crrd.h"
59+
5860
#ifdef __cplusplus
5961
extern "C" {
6062
#endif
@@ -343,6 +345,12 @@ struct spa {
343345
spa_checkpoint_info_t spa_checkpoint_info; /* checkpoint accounting */
344346
zthr_t *spa_checkpoint_discard_zthr;
345347

348+
kmutex_t spa_txg_log_time_lock; /* for spa_txg_log_time */
349+
dbrrd_t spa_txg_log_time;
350+
uint64_t spa_last_noted_txg;
351+
uint64_t spa_last_noted_txg_time;
352+
uint64_t spa_last_flush_txg_time;
353+
346354
space_map_t *spa_syncing_log_sm; /* current log space map */
347355
avl_tree_t spa_sm_logs_by_txg;
348356
kmutex_t spa_flushed_ms_lock; /* for metaslabs_by_flushed */

include/zfs_crrd.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: CDDL-1.0
2+
/*
3+
* CDDL HEADER START
4+
*
5+
* The contents of this file are subject to the terms of the
6+
* Common Development and Distribution License (the "License").
7+
* You may not use this file except in compliance with the License.
8+
*
9+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10+
* or https://opensource.org/licenses/CDDL-1.0.
11+
* See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*
14+
* When distributing Covered Code, include this CDDL HEADER in each
15+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16+
* If applicable, add the following below this CDDL HEADER, with the
17+
* fields enclosed by brackets "[]" replaced with your own identifying
18+
* information: Portions Copyright [yyyy] [name of copyright owner]
19+
*
20+
* CDDL HEADER END
21+
*/
22+
/*
23+
* Copyright (c) 2024 Klara Inc.
24+
*
25+
* This software was developed by
26+
* Fred Weigel <[email protected]>
27+
* Mariusz Zaborski <[email protected]>
28+
* under sponsorship from Wasabi Technology, Inc. and Klara Inc.
29+
*/
30+
31+
#ifndef _CRRD_H_
32+
#define _CRRD_H_
33+
34+
#define RRD_MAX_ENTRIES 256
35+
36+
#define RRD_ENTRY_SIZE sizeof (uint64_t)
37+
#define RRD_STRUCT_ELEM (sizeof (rrd_t) / RRD_ENTRY_SIZE)
38+
39+
typedef enum {
40+
DBRRD_FLOOR,
41+
DBRRD_CEILING
42+
} dbrrd_rounding_t;
43+
44+
typedef struct {
45+
uint64_t rrdd_time;
46+
uint64_t rrdd_txg;
47+
} rrd_data_t;
48+
49+
typedef struct {
50+
uint64_t rrd_head; /* head (beginning) */
51+
uint64_t rrd_tail; /* tail (end) */
52+
uint64_t rrd_length;
53+
54+
rrd_data_t rrd_entries[RRD_MAX_ENTRIES];
55+
} rrd_t;
56+
57+
typedef struct {
58+
rrd_t dbr_minutes;
59+
rrd_t dbr_days;
60+
rrd_t dbr_months;
61+
} dbrrd_t;
62+
63+
size_t rrd_len(rrd_t *rrd);
64+
65+
const rrd_data_t *rrd_entry(rrd_t *r, size_t i);
66+
const rrd_data_t *rrd_tail_entry(rrd_t *rrd);
67+
uint64_t rrd_tail(rrd_t *rrd);
68+
uint64_t rrd_get(rrd_t *rrd, size_t i);
69+
70+
void rrd_add(rrd_t *rrd, hrtime_t time, uint64_t txg);
71+
72+
void dbrrd_add(dbrrd_t *db, hrtime_t time, uint64_t txg);
73+
uint64_t dbrrd_query(dbrrd_t *r, hrtime_t tv, dbrrd_rounding_t rouding);
74+
75+
#endif

lib/libzfs/libzfs.abi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6702,6 +6702,8 @@
67026702
<parameter type-id='4c81de99' name='zhp'/>
67036703
<parameter type-id='7313fbe2' name='func'/>
67046704
<parameter type-id='b51cf3c2' name='cmd'/>
6705+
<parameter type-id='c9d12d66' name='date_start'/>
6706+
<parameter type-id='c9d12d66' name='date_end'/>
67056707
<return type-id='95e97e5e'/>
67066708
</function-decl>
67076709
<function-decl name='zpool_find_vdev_by_physpath' mangled-name='zpool_find_vdev_by_physpath' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_find_vdev_by_physpath'>

lib/libzfs/libzfs_pool.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2730,7 +2730,8 @@ zpool_trim(zpool_handle_t *zhp, pool_trim_func_t cmd_type, nvlist_t *vds,
27302730
* Scan the pool.
27312731
*/
27322732
int
2733-
zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
2733+
zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd,
2734+
time_t date_start, time_t date_end)
27342735
{
27352736
char errbuf[ERRBUFLEN];
27362737
int err;
@@ -2739,6 +2740,8 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
27392740
nvlist_t *args = fnvlist_alloc();
27402741
fnvlist_add_uint64(args, "scan_type", (uint64_t)func);
27412742
fnvlist_add_uint64(args, "scan_command", (uint64_t)cmd);
2743+
fnvlist_add_uint64(args, "scan_date_start", (uint64_t)date_start);
2744+
fnvlist_add_uint64(args, "scan_date_end", (uint64_t)date_end);
27422745

27432746
err = lzc_scrub(ZFS_IOC_POOL_SCRUB, zhp->zpool_name, args, NULL);
27442747
fnvlist_free(args);

lib/libzpool/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ nodist_libzpool_la_SOURCES = \
179179
module/zfs/zfs_byteswap.c \
180180
module/zfs/zfs_chksum.c \
181181
module/zfs/zfs_debug_common.c \
182+
module/zfs/zfs_crrd.c \
182183
module/zfs/zfs_fm.c \
183184
module/zfs/zfs_fuid.c \
184185
module/zfs/zfs_ratelimit.c \

man/man8/zpool-scrub.8

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
.\" Copyright 2017 Nexenta Systems, Inc.
2828
.\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
2929
.\"
30-
.Dd November 18, 2024
30+
.Dd December 11, 2024
3131
.Dt ZPOOL-SCRUB 8
3232
.Os
3333
.
@@ -39,6 +39,8 @@
3939
.Cm scrub
4040
.Op Ns Fl e | Ns Fl p | Fl s Ns | Fl C Ns
4141
.Op Fl w
42+
.Op Fl S Ar date
43+
.Op Fl E Ar date
4244
.Ar pool Ns
4345
.
4446
.Sh DESCRIPTION
@@ -109,15 +111,49 @@ Wait until scrub has completed before returning.
109111
.It Fl e
110112
Only scrub files with known data errors as reported by
111113
.Nm zpool Cm status Fl v .
112-
The pool must have been scrubbed at least once with the
113-
.Sy head_errlog
114-
feature enabled to use this option.
115114
Error scrubbing cannot be run simultaneously with regular scrubbing or
116115
resilvering, nor can it be run when a regular scrub is paused.
117116
.It Fl C
118117
Continue scrub from last saved txg (see zpool
119118
.Sy last_scrubbed_txg
120119
property).
120+
.It Fl S Ar date , Fl E Ar date
121+
Allows specifying the date range for blocks created between these dates.
122+
.Bl -bullet -compact -offset indent
123+
.It
124+
.Fl S
125+
Defines a start date.
126+
If not specified, scrubbing begins from the start of the pool's
127+
existence.
128+
.It
129+
.Fl E
130+
Defines an end date.
131+
If not specified, scrubbing continues up to the most recent data.
132+
.El
133+
The provided date should be in the format:
134+
.Dq YYYY-MM-DD HH:MM .
135+
Where:
136+
.Bl -bullet -compact -offset indent
137+
.It
138+
.Dq YYYY
139+
is the year.
140+
.It
141+
.Dq MM
142+
is the numeric representation of the month.
143+
.It
144+
.Dq DD
145+
is the day of the month.
146+
.It
147+
.Dq HH
148+
is the hour.
149+
.It
150+
.Dq MM
151+
is the minutes.
152+
.El
153+
The hour and minutes parameters can be omitted.
154+
The time should be provided in machine local time zone.
155+
Specifying dates prior to enabling this feature will result in scrubbing
156+
starting from the date the pool was created.
121157
.El
122158
.Sh EXAMPLES
123159
.Ss Example 1

module/Kbuild.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ ZFS_OBJS := \
414414
zfs_byteswap.o \
415415
zfs_chksum.o \
416416
zfs_debug_common.o \
417+
zfs_crrd.o \
417418
zfs_fm.o \
418419
zfs_fuid.o \
419420
zfs_impl.o \

module/Makefile.bsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ SRCS+= abd_os.c \
217217
vdev_label_os.c \
218218
zfs_acl.c \
219219
zfs_ctldir.c \
220+
zfs_crrd.c \
220221
zfs_debug.c \
221222
zfs_dir.c \
222223
zfs_file_os.c \

0 commit comments

Comments
 (0)