Skip to content

Commit c60d233

Browse files
committed
Add BRT support to zpool prefetch command
Implement BRT (Block Reference Table) prefetch functionality similar to existing DDT prefetch. This allows preloading BRT metadata into ARC to improve performance for block cloning operations and frees of earlier cloned blocks. Make -t parameter optional. When omitted, prefetch all supported metadata types (both DDT and BRT now). Signed-off-by: Alexander Motin <alexander.motin@TrueNAS.com>
1 parent 6cfc3db commit c60d233

File tree

8 files changed

+90
-38
lines changed

8 files changed

+90
-38
lines changed

cmd/zpool/zpool_main.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -494,8 +494,7 @@ get_usage(zpool_help_t idx)
494494
"[--json-int, --json-pool-key-guid]] ...\n"
495495
"\t [-T d|u] [pool] [interval [count]]\n"));
496496
case HELP_PREFETCH:
497-
return (gettext("\tprefetch -t <type> [<type opts>] <pool>\n"
498-
"\t -t ddt <pool>\n"));
497+
return (gettext("\tprefetch [-t <type>] <pool>\n"));
499498
case HELP_OFFLINE:
500499
return (gettext("\toffline [--power]|[[-f][-t]] <pool> "
501500
"<device> ...\n"));
@@ -4245,20 +4244,27 @@ zpool_do_prefetch(int argc, char **argv)
42454244

42464245
poolname = argv[0];
42474246

4248-
argc--;
4249-
argv++;
4250-
4251-
if (strcmp(typestr, "ddt") == 0) {
4252-
type = ZPOOL_PREFETCH_DDT;
4253-
} else {
4254-
(void) fprintf(stderr, gettext("unsupported prefetch type\n"));
4255-
usage(B_FALSE);
4256-
}
4257-
42584247
if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
42594248
return (1);
42604249

4261-
err = zpool_prefetch(zhp, type);
4250+
if (typestr == NULL) {
4251+
/* Prefetch all types */
4252+
err = zpool_prefetch(zhp, ZPOOL_PREFETCH_DDT);
4253+
if (err == 0)
4254+
err = zpool_prefetch(zhp, ZPOOL_PREFETCH_BRT);
4255+
} else {
4256+
if (strcmp(typestr, "ddt") == 0) {
4257+
type = ZPOOL_PREFETCH_DDT;
4258+
} else if (strcmp(typestr, "brt") == 0) {
4259+
type = ZPOOL_PREFETCH_BRT;
4260+
} else {
4261+
(void) fprintf(stderr,
4262+
gettext("unsupported prefetch type\n"));
4263+
zpool_close(zhp);
4264+
usage(B_FALSE);
4265+
}
4266+
err = zpool_prefetch(zhp, type);
4267+
}
42624268

42634269
zpool_close(zhp);
42644270

include/sys/brt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ extern void brt_create(spa_t *spa);
5656
extern int brt_load(spa_t *spa);
5757
extern void brt_unload(spa_t *spa);
5858
extern void brt_sync(spa_t *spa, uint64_t txg);
59+
extern void brt_prefetch_all(spa_t *spa);
5960

6061
#ifdef __cplusplus
6162
}

include/sys/fs/zfs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1713,7 +1713,8 @@ typedef enum {
17131713

17141714
typedef enum {
17151715
ZPOOL_PREFETCH_NONE = 0,
1716-
ZPOOL_PREFETCH_DDT
1716+
ZPOOL_PREFETCH_DDT,
1717+
ZPOOL_PREFETCH_BRT
17171718
} zpool_prefetch_type_t;
17181719

17191720
typedef enum {

lib/libzfs/libzfs_pool.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,9 +1745,13 @@ zpool_prefetch(zpool_handle_t *zhp, zpool_prefetch_type_t type)
17451745

17461746
error = lzc_pool_prefetch(zhp->zpool_name, type);
17471747
if (error != 0) {
1748+
const char *typename = "unknown";
1749+
if (type == ZPOOL_PREFETCH_DDT)
1750+
typename = "ddt";
1751+
else if (type == ZPOOL_PREFETCH_BRT)
1752+
typename = "brt";
17481753
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1749-
"cannot prefetch %s in '%s'"),
1750-
type == ZPOOL_PREFETCH_DDT ? "ddt" : "", zhp->zpool_name);
1754+
"cannot prefetch %s in '%s'"), typename, zhp->zpool_name);
17511755
(void) zpool_standard_error(hdl, error, msg);
17521756
return (-1);
17531757
}

man/man8/zpool-prefetch.8

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,25 @@
2828
.
2929
.Sh NAME
3030
.Nm zpool-prefetch
31-
.Nd Loads specific types of data for the given pool
31+
.Nd Prefetches pool metadata into ARC
3232
.Sh SYNOPSIS
3333
.Nm zpool
3434
.Cm prefetch
35-
.Fl t Ar type
35+
.Op Fl t Ar type
3636
.Ar pool
3737
.Sh DESCRIPTION
38-
.Bl -tag -width Ds
39-
.It Xo
40-
.Nm zpool
41-
.Cm prefetch
42-
.Fl t Li ddt
43-
.Ar pool
44-
.Xc
45-
Prefetch data of a specific type for the given pool; specifically the DDT,
46-
which will improve write I/O performance when the DDT is resident in the ARC.
38+
Massively prefetch metadata of a specific type for the given pool into the ARC
39+
to reduce latency of some operations later.
40+
If no type is specified, all types are prefetched.
41+
.Pp
42+
The following types are supported:
43+
.Bl -tag -width "brt"
44+
.It Sy brt
45+
Prefetch the BRT (block reference table).
46+
This may improve performance for block cloning operations,
47+
and frees for earlier cloned blocks.
48+
.It Sy ddt
49+
Prefetch the DDT (deduplication table).
50+
This may improve performance of writes when deduplication is enabled,
51+
and frees for earlier deduplicated blocks.
4752
.El

module/zfs/brt.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,31 @@ brt_load(spa_t *spa)
15101510
return (error);
15111511
}
15121512

1513+
void
1514+
brt_prefetch_all(spa_t *spa)
1515+
{
1516+
/*
1517+
* Load all BRT entries for each vdev. This is intended to perform
1518+
* a prefetch on all such blocks. For the same reason that brt_prefetch
1519+
* (called from brt_pending_add) isn't locked, this is also not locked.
1520+
*/
1521+
brt_rlock(spa);
1522+
for (uint64_t vdevid = 0; vdevid < spa->spa_brt_nvdevs; vdevid++) {
1523+
brt_vdev_t *brtvd = spa->spa_brt_vdevs[vdevid];
1524+
brt_unlock(spa);
1525+
1526+
rw_enter(&brtvd->bv_mos_entries_lock, RW_READER);
1527+
if (brtvd->bv_mos_entries != 0) {
1528+
(void) zap_prefetch_object(spa->spa_meta_objset,
1529+
brtvd->bv_mos_entries);
1530+
}
1531+
rw_exit(&brtvd->bv_mos_entries_lock);
1532+
1533+
brt_rlock(spa);
1534+
}
1535+
brt_unlock(spa);
1536+
}
1537+
15131538
void
15141539
brt_unload(spa_t *spa)
15151540
{

module/zfs/dmu.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,12 +850,15 @@ dmu_prefetch_wait(objset_t *os, uint64_t object, uint64_t offset, uint64_t size)
850850
return (err);
851851

852852
/*
853-
* Chunk the requests (16 indirects worth) so that we can be interrupted
853+
* Chunk the requests (16 indirects worth) so that we can be
854+
* interrupted. Prefetch at least SPA_MAXBLOCKSIZE at a time
855+
* to better utilize pools with smaller block sizes.
854856
*/
855857
uint64_t chunksize;
856858
if (dn->dn_indblkshift) {
857859
uint64_t nbps = bp_span_in_blocks(dn->dn_indblkshift, 1);
858860
chunksize = (nbps * 16) << dn->dn_datablkshift;
861+
chunksize = MAX(chunksize, SPA_MAXBLOCKSIZE);
859862
} else {
860863
chunksize = dn->dn_datablksz;
861864
}

module/zfs/zfs_ioctl.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@
212212
#include <sys/vdev_impl.h>
213213
#include <sys/vdev_initialize.h>
214214
#include <sys/vdev_trim.h>
215+
#include <sys/brt.h>
216+
#include <sys/ddt.h>
215217

216218
#include "zfs_namecheck.h"
217219
#include "zfs_prop.h"
@@ -4276,24 +4278,29 @@ zfs_ioc_pool_prefetch(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
42764278
spa_t *spa;
42774279
int32_t type;
42784280

4279-
/*
4280-
* Currently, only ZPOOL_PREFETCH_DDT is supported
4281-
*/
4282-
if (nvlist_lookup_int32(innvl, ZPOOL_PREFETCH_TYPE, &type) != 0 ||
4283-
type != ZPOOL_PREFETCH_DDT) {
4281+
if (nvlist_lookup_int32(innvl, ZPOOL_PREFETCH_TYPE, &type) != 0)
4282+
return (EINVAL);
4283+
4284+
if (type != ZPOOL_PREFETCH_DDT && type != ZPOOL_PREFETCH_BRT)
42844285
return (EINVAL);
4285-
}
42864286

42874287
error = spa_open(poolname, &spa, FTAG);
42884288
if (error != 0)
42894289
return (error);
42904290

42914291
hrtime_t start_time = gethrtime();
42924292

4293-
ddt_prefetch_all(spa);
4294-
4295-
zfs_dbgmsg("pool '%s': loaded ddt into ARC in %llu ms", spa->spa_name,
4296-
(u_longlong_t)NSEC2MSEC(gethrtime() - start_time));
4293+
if (type == ZPOOL_PREFETCH_DDT) {
4294+
ddt_prefetch_all(spa);
4295+
zfs_dbgmsg("pool '%s': loaded ddt into ARC in %llu ms",
4296+
spa->spa_name,
4297+
(u_longlong_t)NSEC2MSEC(gethrtime() - start_time));
4298+
} else {
4299+
brt_prefetch_all(spa);
4300+
zfs_dbgmsg("pool '%s': loaded brt into ARC in %llu ms",
4301+
spa->spa_name,
4302+
(u_longlong_t)NSEC2MSEC(gethrtime() - start_time));
4303+
}
42974304

42984305
spa_close(spa, FTAG);
42994306

0 commit comments

Comments
 (0)