Skip to content

Commit b77222c

Browse files
ahrensbehlendorf
authored andcommitted
Illumos 6450 - scrub/resilver unnecessarily traverses snapshots
6450 scrub/resilver unnecessarily traverses snapshots created after the scrub started Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Richard Elling <Richard.Elling@RichardElling.com> Approved by: Richard Lowe <richlowe@richlowe.net> References: https://www.illumos.org/issues/6450 illumos/illumos-gate@38d6103 Ported-by: kernelOfTruth kerneloftruth@gmail.com Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
1 parent 9d36cdb commit b77222c

File tree

1 file changed

+50
-4
lines changed

1 file changed

+50
-4
lines changed

module/zfs/dsl_scan.c

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,16 @@ dsl_scan_ds_destroyed(dsl_dataset_t *ds, dmu_tx_t *tx)
872872

873873
if (scn->scn_phys.scn_bookmark.zb_objset == ds->ds_object) {
874874
if (ds->ds_is_snapshot) {
875-
/* Note, scn_cur_{min,max}_txg stays the same. */
875+
/*
876+
* Note:
877+
* - scn_cur_{min,max}_txg stays the same.
878+
* - Setting the flag is not really necessary if
879+
* scn_cur_max_txg == scn_max_txg, because there
880+
* is nothing after this snapshot that we care
881+
* about. However, we set it anyway and then
882+
* ignore it when we retraverse it in
883+
* dsl_scan_visitds().
884+
*/
876885
scn->scn_phys.scn_bookmark.zb_objset =
877886
dsl_dataset_phys(ds)->ds_next_snap_obj;
878887
zfs_dbgmsg("destroying ds %llu; currently traversing; "
@@ -912,9 +921,6 @@ dsl_scan_ds_destroyed(dsl_dataset_t *ds, dmu_tx_t *tx)
912921
zfs_dbgmsg("destroying ds %llu; in queue; removing",
913922
(u_longlong_t)ds->ds_object);
914923
}
915-
} else {
916-
zfs_dbgmsg("destroying ds %llu; ignoring",
917-
(u_longlong_t)ds->ds_object);
918924
}
919925

920926
/*
@@ -1068,6 +1074,46 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
10681074

10691075
VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
10701076

1077+
if (scn->scn_phys.scn_cur_min_txg >=
1078+
scn->scn_phys.scn_max_txg) {
1079+
/*
1080+
* This can happen if this snapshot was created after the
1081+
* scan started, and we already completed a previous snapshot
1082+
* that was created after the scan started. This snapshot
1083+
* only references blocks with:
1084+
*
1085+
* birth < our ds_creation_txg
1086+
* cur_min_txg is no less than ds_creation_txg.
1087+
* We have already visited these blocks.
1088+
* or
1089+
* birth > scn_max_txg
1090+
* The scan requested not to visit these blocks.
1091+
*
1092+
* Subsequent snapshots (and clones) can reference our
1093+
* blocks, or blocks with even higher birth times.
1094+
* Therefore we do not need to visit them either,
1095+
* so we do not add them to the work queue.
1096+
*
1097+
* Note that checking for cur_min_txg >= cur_max_txg
1098+
* is not sufficient, because in that case we may need to
1099+
* visit subsequent snapshots. This happens when min_txg > 0,
1100+
* which raises cur_min_txg. In this case we will visit
1101+
* this dataset but skip all of its blocks, because the
1102+
* rootbp's birth time is < cur_min_txg. Then we will
1103+
* add the next snapshots/clones to the work queue.
1104+
*/
1105+
char *dsname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1106+
dsl_dataset_name(ds, dsname);
1107+
zfs_dbgmsg("scanning dataset %llu (%s) is unnecessary because "
1108+
"cur_min_txg (%llu) >= max_txg (%llu)",
1109+
dsobj, dsname,
1110+
scn->scn_phys.scn_cur_min_txg,
1111+
scn->scn_phys.scn_max_txg);
1112+
kmem_free(dsname, MAXNAMELEN);
1113+
1114+
goto out;
1115+
}
1116+
10711117
if (dmu_objset_from_ds(ds, &os))
10721118
goto out;
10731119

0 commit comments

Comments
 (0)