Merge 1512020604
into 7ca7bb7fd7
This commit is contained in:
commit
9e0cb8704b
|
@ -112,6 +112,7 @@ static int zfs_do_hold(int argc, char **argv);
|
||||||
static int zfs_do_holds(int argc, char **argv);
|
static int zfs_do_holds(int argc, char **argv);
|
||||||
static int zfs_do_release(int argc, char **argv);
|
static int zfs_do_release(int argc, char **argv);
|
||||||
static int zfs_do_diff(int argc, char **argv);
|
static int zfs_do_diff(int argc, char **argv);
|
||||||
|
static int zfs_do_scrub(int argc, char **argv);
|
||||||
static int zfs_do_bookmark(int argc, char **argv);
|
static int zfs_do_bookmark(int argc, char **argv);
|
||||||
static int zfs_do_channel_program(int argc, char **argv);
|
static int zfs_do_channel_program(int argc, char **argv);
|
||||||
static int zfs_do_load_key(int argc, char **argv);
|
static int zfs_do_load_key(int argc, char **argv);
|
||||||
|
@ -181,6 +182,7 @@ typedef enum {
|
||||||
HELP_HOLDS,
|
HELP_HOLDS,
|
||||||
HELP_RELEASE,
|
HELP_RELEASE,
|
||||||
HELP_DIFF,
|
HELP_DIFF,
|
||||||
|
HELP_SCRUB,
|
||||||
HELP_BOOKMARK,
|
HELP_BOOKMARK,
|
||||||
HELP_CHANNEL_PROGRAM,
|
HELP_CHANNEL_PROGRAM,
|
||||||
HELP_LOAD_KEY,
|
HELP_LOAD_KEY,
|
||||||
|
@ -253,6 +255,7 @@ static zfs_command_t command_table[] = {
|
||||||
{ "holds", zfs_do_holds, HELP_HOLDS },
|
{ "holds", zfs_do_holds, HELP_HOLDS },
|
||||||
{ "release", zfs_do_release, HELP_RELEASE },
|
{ "release", zfs_do_release, HELP_RELEASE },
|
||||||
{ "diff", zfs_do_diff, HELP_DIFF },
|
{ "diff", zfs_do_diff, HELP_DIFF },
|
||||||
|
{ "scrub", zfs_do_scrub, HELP_SCRUB },
|
||||||
{ "load-key", zfs_do_load_key, HELP_LOAD_KEY },
|
{ "load-key", zfs_do_load_key, HELP_LOAD_KEY },
|
||||||
{ "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY },
|
{ "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY },
|
||||||
{ "change-key", zfs_do_change_key, HELP_CHANGE_KEY },
|
{ "change-key", zfs_do_change_key, HELP_CHANGE_KEY },
|
||||||
|
@ -401,6 +404,8 @@ get_usage(zfs_help_t idx)
|
||||||
case HELP_DIFF:
|
case HELP_DIFF:
|
||||||
return (gettext("\tdiff [-FHth] <snapshot> "
|
return (gettext("\tdiff [-FHth] <snapshot> "
|
||||||
"[snapshot|filesystem]\n"));
|
"[snapshot|filesystem]\n"));
|
||||||
|
case HELP_SCRUB:
|
||||||
|
return (gettext("\tscrub <file>\n"));
|
||||||
case HELP_BOOKMARK:
|
case HELP_BOOKMARK:
|
||||||
return (gettext("\tbookmark <snapshot|bookmark> "
|
return (gettext("\tbookmark <snapshot|bookmark> "
|
||||||
"<newbookmark>\n"));
|
"<newbookmark>\n"));
|
||||||
|
@ -7938,6 +7943,98 @@ out:
|
||||||
return (err != 0);
|
return (err != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
scrub_single_file(zfs_handle_t *zhp, void *data)
|
||||||
|
{
|
||||||
|
struct stat64 *filestat = (struct stat64 *)data;
|
||||||
|
struct stat64 mountstat;
|
||||||
|
char mountpoint[ZFS_MAXPROPLEN];
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
|
||||||
|
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat64(mountpoint, &mountstat) < 0) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mountstat.st_dev != filestat->st_dev) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_t *args = fnvlist_alloc();
|
||||||
|
fnvlist_add_string(args, "dataset", zfs_get_name(zhp));
|
||||||
|
fnvlist_add_uint64(args, "object", filestat->st_ino);
|
||||||
|
|
||||||
|
err = lzc_scrub(ZFS_IOC_POOL_SCRUB_FILE, zfs_get_pool_name(zhp),
|
||||||
|
args, NULL);
|
||||||
|
|
||||||
|
fnvlist_free(args);
|
||||||
|
|
||||||
|
return (err != 0 ? 2 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_dataset_and_scrub(zfs_handle_t *zhp, void *data)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = scrub_single_file(zhp, data);
|
||||||
|
if (err == 0) {
|
||||||
|
err = zfs_iter_filesystems_v2(zhp, 0, find_dataset_and_scrub,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
zfs_close(zhp);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* zfs scrub <file>
|
||||||
|
*
|
||||||
|
* Scrubs single file.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
zfs_do_scrub(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *filetoscrub = NULL;
|
||||||
|
struct stat64 filestat;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("must provide a file to scrub\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 2) {
|
||||||
|
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
filetoscrub = argv[1];
|
||||||
|
if (stat64(filetoscrub, &filestat) < 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("must provide a file to scrub\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISREG(filestat.st_mode) == 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("scrub works only on regular files\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = zfs_iter_root(g_zfs, find_dataset_and_scrub, &filestat);
|
||||||
|
if (err == 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("unable to scrub file %s\n"), filetoscrub);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (err == 1 ? 0 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zfs bookmark <fs@source>|<fs#source> <fs#bookmark>
|
* zfs bookmark <fs@source>|<fs#source> <fs#bookmark>
|
||||||
*
|
*
|
||||||
|
|
|
@ -1512,6 +1512,7 @@ typedef enum zfs_ioc {
|
||||||
ZFS_IOC_VDEV_GET_PROPS, /* 0x5a55 */
|
ZFS_IOC_VDEV_GET_PROPS, /* 0x5a55 */
|
||||||
ZFS_IOC_VDEV_SET_PROPS, /* 0x5a56 */
|
ZFS_IOC_VDEV_SET_PROPS, /* 0x5a56 */
|
||||||
ZFS_IOC_POOL_SCRUB, /* 0x5a57 */
|
ZFS_IOC_POOL_SCRUB, /* 0x5a57 */
|
||||||
|
ZFS_IOC_POOL_SCRUB_FILE, /* 0x5a58 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-platform (Optional) - 8/128 numbers reserved.
|
* Per-platform (Optional) - 8/128 numbers reserved.
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
.\"
|
||||||
|
.\" CDDL HEADER START
|
||||||
|
.\"
|
||||||
|
.\" The contents of this file are subject to the terms of the
|
||||||
|
.\" Common Development and Distribution License (the "License").
|
||||||
|
.\" You may not use this file except in compliance with the License.
|
||||||
|
.\"
|
||||||
|
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
.\" or https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
.\" See the License for the specific language governing permissions
|
||||||
|
.\" and limitations under the License.
|
||||||
|
.\"
|
||||||
|
.\" When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
.\" If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
.\" fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
.\" information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
.\"
|
||||||
|
.\" CDDL HEADER END
|
||||||
|
.\"
|
||||||
|
.\" Copyright 2024 Klara, Inc.
|
||||||
|
.\" Copyright 2024 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||||
|
.\"
|
||||||
|
.Dd February 21, 2024
|
||||||
|
.Dt ZFS-SCRUB 8
|
||||||
|
.Os
|
||||||
|
.
|
||||||
|
.Sh NAME
|
||||||
|
.Nm zfs-scrub
|
||||||
|
.Nd run scrub of file in ZFS storage pools
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm zfs
|
||||||
|
.Cm scrub
|
||||||
|
.Ar filename Ns
|
||||||
|
.
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
Runs a scrub for a single file.
|
||||||
|
The scrub examines all data associated with a given file.
|
||||||
|
For replicated
|
||||||
|
.Pq mirror, raidz, or draid
|
||||||
|
devices, ZFS automatically repairs any damage discovered during the scrub.
|
||||||
|
The
|
||||||
|
.Nm zpool Cm status
|
||||||
|
command reports the progress of the scrub and summarizes the results of the
|
||||||
|
scrub upon completion.
|
||||||
|
For more details about scrubing, refer
|
||||||
|
.Xr zpool 8 .
|
||||||
|
.
|
||||||
|
.Pp
|
||||||
|
ZFS allows only on scrub process at a time (pool scrub or file scrub).
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr zpool-scrub 8 ,
|
||||||
|
.Xr zpool-status 8
|
|
@ -275,6 +275,12 @@ Delegate permissions on the specified filesystem or volume.
|
||||||
Remove delegated permissions on the specified filesystem or volume.
|
Remove delegated permissions on the specified filesystem or volume.
|
||||||
.El
|
.El
|
||||||
.
|
.
|
||||||
|
.Ss Maintenance
|
||||||
|
.Bl -tag -width ""
|
||||||
|
.It Xr zfs-scrub 8
|
||||||
|
Runs a scrub of single file.
|
||||||
|
.El
|
||||||
|
.
|
||||||
.Ss Encryption
|
.Ss Encryption
|
||||||
.Bl -tag -width ""
|
.Bl -tag -width ""
|
||||||
.It Xr zfs-change-key 8
|
.It Xr zfs-change-key 8
|
||||||
|
@ -818,6 +824,7 @@ don't wait.
|
||||||
.Xr zfs-release 8 ,
|
.Xr zfs-release 8 ,
|
||||||
.Xr zfs-rename 8 ,
|
.Xr zfs-rename 8 ,
|
||||||
.Xr zfs-rollback 8 ,
|
.Xr zfs-rollback 8 ,
|
||||||
|
.Xr zfs-scrub 8 ,
|
||||||
.Xr zfs-send 8 ,
|
.Xr zfs-send 8 ,
|
||||||
.Xr zfs-set 8 ,
|
.Xr zfs-set 8 ,
|
||||||
.Xr zfs-share 8 ,
|
.Xr zfs-share 8 ,
|
||||||
|
|
|
@ -154,6 +154,7 @@ timer units are provided.
|
||||||
.
|
.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr systemd.timer 5 ,
|
.Xr systemd.timer 5 ,
|
||||||
|
.Xr zfs-scrub 8 ,
|
||||||
.Xr zpool-iostat 8 ,
|
.Xr zpool-iostat 8 ,
|
||||||
.Xr zpool-resilver 8 ,
|
.Xr zpool-resilver 8 ,
|
||||||
.Xr zpool-status 8
|
.Xr zpool-status 8
|
||||||
|
|
|
@ -202,6 +202,7 @@
|
||||||
#include <sys/dmu_recv.h>
|
#include <sys/dmu_recv.h>
|
||||||
#include <sys/dmu_send.h>
|
#include <sys/dmu_send.h>
|
||||||
#include <sys/dmu_recv.h>
|
#include <sys/dmu_recv.h>
|
||||||
|
#include <sys/dbuf.h>
|
||||||
#include <sys/dsl_destroy.h>
|
#include <sys/dsl_destroy.h>
|
||||||
#include <sys/dsl_bookmark.h>
|
#include <sys/dsl_bookmark.h>
|
||||||
#include <sys/dsl_userhold.h>
|
#include <sys/dsl_userhold.h>
|
||||||
|
@ -1727,6 +1728,131 @@ zfs_ioc_pool_scrub(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* inputs:
|
||||||
|
* dataset name of dataset
|
||||||
|
* object object number
|
||||||
|
*/
|
||||||
|
static const zfs_ioc_key_t zfs_keys_pool_scrub_file[] = {
|
||||||
|
{"dataset", DATA_TYPE_STRING, 0},
|
||||||
|
{"object", DATA_TYPE_UINT64, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
scrub_file_traverse(spa_t *spa, blkptr_t *bp, const zbookmark_phys_t *zb)
|
||||||
|
{
|
||||||
|
uint64_t blk_birth = bp->blk_birth;
|
||||||
|
|
||||||
|
if (blk_birth == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spa_log_error(spa, zb, &blk_birth);
|
||||||
|
if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
|
||||||
|
arc_flags_t flags = ARC_FLAG_WAIT;
|
||||||
|
int i;
|
||||||
|
blkptr_t *cbp;
|
||||||
|
int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
|
||||||
|
arc_buf_t *buf;
|
||||||
|
|
||||||
|
if (arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
|
||||||
|
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* recursively visit blocks below this */
|
||||||
|
cbp = buf->b_data;
|
||||||
|
for (i = 0; i < epb; i++, cbp++) {
|
||||||
|
zbookmark_phys_t czb;
|
||||||
|
|
||||||
|
SET_BOOKMARK(&czb, zb->zb_objset, zb->zb_object,
|
||||||
|
zb->zb_level - 1,
|
||||||
|
zb->zb_blkid * epb + i);
|
||||||
|
|
||||||
|
scrub_file_traverse(spa, cbp, &czb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zfs_ioc_pool_scrub_file(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
|
{
|
||||||
|
spa_t *spa;
|
||||||
|
int error;
|
||||||
|
const char *dataset;
|
||||||
|
uint64_t object;
|
||||||
|
objset_t *os;
|
||||||
|
dmu_object_info_t doi;
|
||||||
|
zbookmark_phys_t zb;
|
||||||
|
dmu_buf_t *db = NULL;
|
||||||
|
dnode_t *dn;
|
||||||
|
|
||||||
|
if (nvlist_lookup_string(innvl, "dataset", &dataset) != 0)
|
||||||
|
return (SET_ERROR(EINVAL));
|
||||||
|
if (nvlist_lookup_uint64(innvl, "object", &object) != 0)
|
||||||
|
return (SET_ERROR(EINVAL));
|
||||||
|
|
||||||
|
error = dmu_objset_hold(dataset, FTAG, &os);
|
||||||
|
if (error != 0) {
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
dsl_dataset_long_hold(dmu_objset_ds(os), FTAG);
|
||||||
|
spa = dmu_objset_spa(os);
|
||||||
|
|
||||||
|
if (!spa_feature_is_enabled(spa, SPA_FEATURE_HEAD_ERRLOG)) {
|
||||||
|
dsl_pool_rele(dmu_objset_pool(os), FTAG);
|
||||||
|
dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
|
||||||
|
dsl_dataset_rele_flags(dmu_objset_ds(os), 0, FTAG);
|
||||||
|
return (SET_ERROR(ENOTSUP));
|
||||||
|
}
|
||||||
|
|
||||||
|
error = dmu_object_info(os, object, &doi);
|
||||||
|
if (error != 0) {
|
||||||
|
dsl_pool_rele(dmu_objset_pool(os), FTAG);
|
||||||
|
dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
|
||||||
|
dsl_dataset_rele_flags(dmu_objset_ds(os), 0, FTAG);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
if (doi.doi_type != DMU_OT_PLAIN_FILE_CONTENTS) {
|
||||||
|
dsl_pool_rele(dmu_objset_pool(os), FTAG);
|
||||||
|
dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
|
||||||
|
dsl_dataset_rele_flags(dmu_objset_ds(os), 0, FTAG);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = dmu_bonus_hold(os, object, FTAG, &db);
|
||||||
|
if (error != 0) {
|
||||||
|
dsl_pool_rele(dmu_objset_pool(os), FTAG);
|
||||||
|
dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
|
||||||
|
dsl_dataset_rele_flags(dmu_objset_ds(os), 0, FTAG);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
dn = DB_DNODE((dmu_buf_impl_t *)db);
|
||||||
|
|
||||||
|
zb.zb_objset = dmu_objset_id(os);
|
||||||
|
zb.zb_object = object;
|
||||||
|
|
||||||
|
dmu_buf_rele(db, FTAG);
|
||||||
|
|
||||||
|
for (int j = 0; j < dn->dn_phys->dn_nblkptr; j++) {
|
||||||
|
zb.zb_blkid = j;
|
||||||
|
zb.zb_level = BP_GET_LEVEL(&dn->dn_phys->dn_blkptr[j]);
|
||||||
|
scrub_file_traverse(spa, &dn->dn_phys->dn_blkptr[j], &zb);
|
||||||
|
}
|
||||||
|
|
||||||
|
dsl_pool_rele(dmu_objset_pool(os), FTAG);
|
||||||
|
dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
|
||||||
|
dsl_dataset_rele_flags(dmu_objset_ds(os), 0, FTAG);
|
||||||
|
|
||||||
|
txg_wait_synced(spa_get_dsl(spa), 0);
|
||||||
|
|
||||||
|
if ((error = spa_open(poolname, &spa, FTAG)) != 0)
|
||||||
|
return (error);
|
||||||
|
error = spa_scan(spa, POOL_SCAN_ERRORSCRUB);
|
||||||
|
spa_close(spa, FTAG);
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
zfs_ioc_pool_freeze(zfs_cmd_t *zc)
|
zfs_ioc_pool_freeze(zfs_cmd_t *zc)
|
||||||
{
|
{
|
||||||
|
@ -7328,6 +7454,11 @@ zfs_ioctl_init(void)
|
||||||
POOL_CHECK_NONE, B_TRUE, B_TRUE,
|
POOL_CHECK_NONE, B_TRUE, B_TRUE,
|
||||||
zfs_keys_pool_scrub, ARRAY_SIZE(zfs_keys_pool_scrub));
|
zfs_keys_pool_scrub, ARRAY_SIZE(zfs_keys_pool_scrub));
|
||||||
|
|
||||||
|
zfs_ioctl_register("scrub_file", ZFS_IOC_POOL_SCRUB_FILE,
|
||||||
|
zfs_ioc_pool_scrub_file, zfs_secpolicy_config, POOL_NAME,
|
||||||
|
POOL_CHECK_NONE, B_TRUE, B_TRUE,
|
||||||
|
zfs_keys_pool_scrub_file, ARRAY_SIZE(zfs_keys_pool_scrub_file));
|
||||||
|
|
||||||
/* IOCTLS that use the legacy function signature */
|
/* IOCTLS that use the legacy function signature */
|
||||||
|
|
||||||
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
|
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
|
||||||
|
|
|
@ -302,6 +302,10 @@ tests = ['zfs_rollback_001_pos', 'zfs_rollback_002_pos',
|
||||||
'zfs_rollback_003_neg', 'zfs_rollback_004_neg']
|
'zfs_rollback_003_neg', 'zfs_rollback_004_neg']
|
||||||
tags = ['functional', 'cli_root', 'zfs_rollback']
|
tags = ['functional', 'cli_root', 'zfs_rollback']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zfs_scrub]
|
||||||
|
tests = ['zfs_error_scrub_001_pos', 'zfs_error_scrub_002_pos']
|
||||||
|
tags = ['functional', 'cli_root', 'zfs_scrub']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_send]
|
[tests/functional/cli_root/zfs_send]
|
||||||
tests = ['zfs_send_001_pos', 'zfs_send_002_pos', 'zfs_send_003_pos',
|
tests = ['zfs_send_001_pos', 'zfs_send_002_pos', 'zfs_send_003_pos',
|
||||||
'zfs_send_004_neg', 'zfs_send_005_pos', 'zfs_send_006_pos',
|
'zfs_send_004_neg', 'zfs_send_005_pos', 'zfs_send_006_pos',
|
||||||
|
|
|
@ -1989,6 +1989,7 @@ function check_pool_status # pool token keyword <verbose>
|
||||||
|
|
||||||
#
|
#
|
||||||
# The following functions are instance of check_pool_status()
|
# The following functions are instance of check_pool_status()
|
||||||
|
# if_pool_without_errors - to check if the pool has errors
|
||||||
# is_pool_resilvering - to check if the pool resilver is in progress
|
# is_pool_resilvering - to check if the pool resilver is in progress
|
||||||
# is_pool_resilvered - to check if the pool resilver is completed
|
# is_pool_resilvered - to check if the pool resilver is completed
|
||||||
# is_pool_scrubbing - to check if the pool scrub is in progress
|
# is_pool_scrubbing - to check if the pool scrub is in progress
|
||||||
|
@ -2000,6 +2001,13 @@ function check_pool_status # pool token keyword <verbose>
|
||||||
# is_pool_discarding - to check if the pool checkpoint is being discarded
|
# is_pool_discarding - to check if the pool checkpoint is being discarded
|
||||||
# is_pool_replacing - to check if the pool is performing a replacement
|
# is_pool_replacing - to check if the pool is performing a replacement
|
||||||
#
|
#
|
||||||
|
|
||||||
|
function is_pool_without_errors #pool <verbose>
|
||||||
|
{
|
||||||
|
check_pool_status "$1" "errors" "No known data errors" $2
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
function is_pool_resilvering #pool <verbose>
|
function is_pool_resilvering #pool <verbose>
|
||||||
{
|
{
|
||||||
check_pool_status "$1" "scan" \
|
check_pool_status "$1" "scan" \
|
||||||
|
|
|
@ -853,6 +853,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/cli_root/zfs_rollback/zfs_rollback_002_pos.ksh \
|
functional/cli_root/zfs_rollback/zfs_rollback_002_pos.ksh \
|
||||||
functional/cli_root/zfs_rollback/zfs_rollback_003_neg.ksh \
|
functional/cli_root/zfs_rollback/zfs_rollback_003_neg.ksh \
|
||||||
functional/cli_root/zfs_rollback/zfs_rollback_004_neg.ksh \
|
functional/cli_root/zfs_rollback/zfs_rollback_004_neg.ksh \
|
||||||
|
functional/cli_root/zfs_scrub/cleanup.ksh \
|
||||||
|
functional/cli_root/zfs_scrub/setup.ksh \
|
||||||
|
functional/cli_root/zfs_scrub/zfs_error_scrub_001_pos.ksh \
|
||||||
|
functional/cli_root/zfs_scrub/zfs_error_scrub_002_pos.ksh \
|
||||||
functional/cli_root/zfs_send/cleanup.ksh \
|
functional/cli_root/zfs_send/cleanup.ksh \
|
||||||
functional/cli_root/zfs_send/setup.ksh \
|
functional/cli_root/zfs_send/setup.ksh \
|
||||||
functional/cli_root/zfs_send/zfs_send_001_pos.ksh \
|
functional/cli_root/zfs_send/zfs_send_001_pos.ksh \
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2024 Klara, Inc.
|
||||||
|
# Copyright 2024 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
default_cleanup
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2024 Klara, Inc.
|
||||||
|
# Copyright 2024 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
DISK=${DISKS%% *}
|
||||||
|
|
||||||
|
default_setup $DISK
|
|
@ -0,0 +1,89 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
# Copyright 2024 Klara, Inc.
|
||||||
|
# Copyright 2024 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Verify scrubbing a single file feature. One file uses indirect
|
||||||
|
# blocks, and second doesn't.
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create a pool.
|
||||||
|
# 2. Create a 10MB file in it (not using indirect blocks).
|
||||||
|
# 3. Create a 1GB file in it (using indirect blocks).
|
||||||
|
# 4. Inject write errors on the small file.
|
||||||
|
# 5. Start a scrub on a 10MB file.
|
||||||
|
# 6. Verify that the file was reported as a buggy.
|
||||||
|
# 7. Clear errors.
|
||||||
|
# 8. Inject write errors on the small file.
|
||||||
|
# 9. Start a scrub on a 1GB file.
|
||||||
|
# 10. Verify that the file was reported as a buggy.
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
log_must zinject -c all
|
||||||
|
rm -f /$TESTPOOL/10m_file
|
||||||
|
log_must zpool clear $TESTPOOL
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_assert "Verify small and large file scrub"
|
||||||
|
|
||||||
|
# To automatically determine the pool in which a file resides, access to the
|
||||||
|
# list of pools is required.
|
||||||
|
unset __ZFS_POOL_EXCLUDE
|
||||||
|
export __ZFS_POOL_RESTRICT="$TESTPOOL"
|
||||||
|
|
||||||
|
log_must fio --rw=write --name=job --size=10M --filename=/$TESTPOOL/10m_file
|
||||||
|
log_must fio --rw=write --name=job --size=1G --filename=/$TESTPOOL/1G_file
|
||||||
|
|
||||||
|
log_must sync_pool $TESTPOOL
|
||||||
|
|
||||||
|
log_must zinject -t data -e checksum -f 100 -am /$TESTPOOL/10m_file
|
||||||
|
|
||||||
|
# check that small file is faulty
|
||||||
|
log_must is_pool_without_errors $TESTPOOL true
|
||||||
|
log_must zfs scrub /$TESTPOOL/10m_file
|
||||||
|
log_must zpool wait -t scrub $TESTPOOL
|
||||||
|
log_mustnot is_pool_without_errors $TESTPOOL true
|
||||||
|
|
||||||
|
# clear errors on small file
|
||||||
|
log_must zinject -c all
|
||||||
|
log_must zfs scrub /$TESTPOOL/10m_file
|
||||||
|
log_must zpool wait -t scrub $TESTPOOL
|
||||||
|
|
||||||
|
# check that large file is faulty
|
||||||
|
log_must zinject -t data -e checksum -f 100 -am /$TESTPOOL/1G_file
|
||||||
|
log_must is_pool_without_errors $TESTPOOL true
|
||||||
|
log_must zfs scrub /$TESTPOOL/1G_file
|
||||||
|
log_must zpool wait -t scrub $TESTPOOL
|
||||||
|
log_mustnot is_pool_without_errors $TESTPOOL true
|
||||||
|
|
||||||
|
log_pass "Verified file scrub shows expected status."
|
|
@ -0,0 +1,72 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
# Copyright 2024 Klara, Inc.
|
||||||
|
# Copyright 2024 Mariusz Zaborski <oshogbo@FreeBSD.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Scrub a single file and self-healing using additional copies.
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create a dataset with copies=3
|
||||||
|
# 2. Write a file to the dataset
|
||||||
|
# 3. zinject errors into the first and second DVAs of that file
|
||||||
|
# 4. Scrub single file and verify the scrub repaired all errors
|
||||||
|
# 5. Remove the zinject handler
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "global"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
log_must zinject -c all
|
||||||
|
destroy_dataset $TESTPOOL/$TESTFS2
|
||||||
|
log_must zpool clear $TESTPOOL
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_assert "Verify scrubing a single file with additional copies"
|
||||||
|
|
||||||
|
# To automatically determine the pool in which a file resides, access to the
|
||||||
|
# list of pools is required.
|
||||||
|
unset __ZFS_POOL_EXCLUDE
|
||||||
|
export __ZFS_POOL_RESTRICT="$TESTPOOL"
|
||||||
|
|
||||||
|
log_must zfs create -o copies=3 $TESTPOOL/$TESTFS2
|
||||||
|
typeset mntpnt=$(get_prop mountpoint $TESTPOOL/$TESTFS2)
|
||||||
|
|
||||||
|
log_must fio --rw=write --name=job --size=10M --filename=$mntpnt/file
|
||||||
|
log_must sync_pool $TESTPOOL
|
||||||
|
|
||||||
|
log_must zinject -a -t data -C 0,1 -e io $mntpnt/file
|
||||||
|
|
||||||
|
log_must zfs scrub $mntpnt/file
|
||||||
|
log_must is_pool_without_errors $TESTPOOL true
|
||||||
|
|
||||||
|
log_must fio --rw=write --name=job --size=10M --filename=$mntpnt/file
|
||||||
|
log_must is_pool_without_errors $TESTPOOL true
|
||||||
|
|
||||||
|
log_pass "Verified file scrub shows expected status."
|
Loading…
Reference in New Issue