1*d0b3ecdcSMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2*d0b3ecdcSMartin Matuska /*
3*d0b3ecdcSMartin Matuska * CDDL HEADER START
4*d0b3ecdcSMartin Matuska *
5*d0b3ecdcSMartin Matuska * This file and its contents are supplied under the terms of the Common
6*d0b3ecdcSMartin Matuska * Development and Distribution License ("CDDL"), version 1.0. You may only use
7*d0b3ecdcSMartin Matuska * this file in accordance with the terms of version 1.0 of the CDDL.
8*d0b3ecdcSMartin Matuska *
9*d0b3ecdcSMartin Matuska * A full copy of the text of the CDDL should have accompanied this source. A
10*d0b3ecdcSMartin Matuska * copy of the CDDL is also available via the Internet at
11*d0b3ecdcSMartin Matuska * http://www.illumos.org/license/CDDL.
12*d0b3ecdcSMartin Matuska *
13*d0b3ecdcSMartin Matuska * CDDL HEADER END
14*d0b3ecdcSMartin Matuska */
15*d0b3ecdcSMartin Matuska
16*d0b3ecdcSMartin Matuska /*
17*d0b3ecdcSMartin Matuska * Copyright (c) 2026 by Garth Snyder. All rights reserved.
18*d0b3ecdcSMartin Matuska */
19*d0b3ecdcSMartin Matuska
20*d0b3ecdcSMartin Matuska #include <assert.h>
21*d0b3ecdcSMartin Matuska #include <err.h>
22*d0b3ecdcSMartin Matuska #include <stdio.h>
23*d0b3ecdcSMartin Matuska #include <stdlib.h>
24*d0b3ecdcSMartin Matuska #include <sys/stdtypes.h>
25*d0b3ecdcSMartin Matuska #include <sys/zfs_ioctl.h>
26*d0b3ecdcSMartin Matuska #include <sys/zio_compress.h>
27*d0b3ecdcSMartin Matuska
28*d0b3ecdcSMartin Matuska #include "zstream_modules.h"
29*d0b3ecdcSMartin Matuska
30*d0b3ecdcSMartin Matuska /*
31*d0b3ecdcSMartin Matuska * Validate consistency and well-formedness of the actual DRR records. I
32*d0b3ecdcSMartin Matuska * have swept all the existing validation code into this module, but it's
33*d0b3ecdcSMartin Matuska * still pretty sparse.
34*d0b3ecdcSMartin Matuska */
35*d0b3ecdcSMartin Matuska
36*d0b3ecdcSMartin Matuska #define MAX_VALIDATIONS 4
37*d0b3ecdcSMartin Matuska
38*d0b3ecdcSMartin Matuska typedef struct {
39*d0b3ecdcSMartin Matuska int nesting;
40*d0b3ecdcSMartin Matuska } validate_context_t;
41*d0b3ecdcSMartin Matuska
42*d0b3ecdcSMartin Matuska static validate_context_t contexts[MAX_VALIDATIONS];
43*d0b3ecdcSMartin Matuska static int next_context = 0;
44*d0b3ecdcSMartin Matuska
45*d0b3ecdcSMartin Matuska static disposition_t
chain_validate_records(drr_packet_t * item,validate_context_t * context)46*d0b3ecdcSMartin Matuska chain_validate_records(drr_packet_t *item, validate_context_t *context)
47*d0b3ecdcSMartin Matuska {
48*d0b3ecdcSMartin Matuska if (item == NULL)
49*d0b3ecdcSMartin Matuska return (D_OK);
50*d0b3ecdcSMartin Matuska
51*d0b3ecdcSMartin Matuska struct dmu_replay_record *drr = &item->dp_drr;
52*d0b3ecdcSMartin Matuska struct drr_write *drrw = &drr->drr_u.drr_write;
53*d0b3ecdcSMartin Matuska struct drr_object *drro = &drr->drr_u.drr_object;
54*d0b3ecdcSMartin Matuska
55*d0b3ecdcSMartin Matuska if (OPTION_ENABLED(CA_DO_NOT_VALIDATE))
56*d0b3ecdcSMartin Matuska return (D_OK);
57*d0b3ecdcSMartin Matuska
58*d0b3ecdcSMartin Matuska if (item->dp_stream_offset == 0 && drr->drr_type != DRR_BEGIN) {
59*d0b3ecdcSMartin Matuska warnx("warning - first record is not DRR_BEGIN");
60*d0b3ecdcSMartin Matuska }
61*d0b3ecdcSMartin Matuska
62*d0b3ecdcSMartin Matuska if (drr->drr_type == DRR_BEGIN) {
63*d0b3ecdcSMartin Matuska VERIFY0(context->nesting);
64*d0b3ecdcSMartin Matuska context->nesting++;
65*d0b3ecdcSMartin Matuska } else if (drr->drr_type == DRR_END) {
66*d0b3ecdcSMartin Matuska VERIFY3S(context->nesting, >=, 0);
67*d0b3ecdcSMartin Matuska if (context->nesting > 0)
68*d0b3ecdcSMartin Matuska context->nesting--;
69*d0b3ecdcSMartin Matuska } else if (drr->drr_type >= DRR_NUMTYPES) {
70*d0b3ecdcSMartin Matuska errx(1, "unknown record type: %d", drr->drr_type);
71*d0b3ecdcSMartin Matuska } else {
72*d0b3ecdcSMartin Matuska VERIFY3S(context->nesting, ==, 1);
73*d0b3ecdcSMartin Matuska }
74*d0b3ecdcSMartin Matuska
75*d0b3ecdcSMartin Matuska switch (drr->drr_type) {
76*d0b3ecdcSMartin Matuska
77*d0b3ecdcSMartin Matuska case DRR_BEGIN:
78*d0b3ecdcSMartin Matuska VERIFY3U(item->dp_payload_size, <=, 1UL << 28);
79*d0b3ecdcSMartin Matuska break;
80*d0b3ecdcSMartin Matuska
81*d0b3ecdcSMartin Matuska case DRR_OBJECT:
82*d0b3ecdcSMartin Matuska {
83*d0b3ecdcSMartin Matuska boolean_t is_raw = !!(chain_attrs->ca_feature_flags &
84*d0b3ecdcSMartin Matuska DMU_BACKUP_FEATURE_RAW);
85*d0b3ecdcSMartin Matuska boolean_t bonus_gt_raw = drro->drr_bonuslen >
86*d0b3ecdcSMartin Matuska drro->drr_raw_bonuslen;
87*d0b3ecdcSMartin Matuska if (is_raw && bonus_gt_raw) {
88*d0b3ecdcSMartin Matuska fprintf(stderr,
89*d0b3ecdcSMartin Matuska "Warning: object %llu has bonuslen = "
90*d0b3ecdcSMartin Matuska "%u > raw_bonuslen = %u\n\n",
91*d0b3ecdcSMartin Matuska (u_longlong_t)drro->drr_object,
92*d0b3ecdcSMartin Matuska drro->drr_bonuslen,
93*d0b3ecdcSMartin Matuska drro->drr_raw_bonuslen);
94*d0b3ecdcSMartin Matuska }
95*d0b3ecdcSMartin Matuska break;
96*d0b3ecdcSMartin Matuska }
97*d0b3ecdcSMartin Matuska
98*d0b3ecdcSMartin Matuska case DRR_WRITE:
99*d0b3ecdcSMartin Matuska if (drrw->drr_compressiontype >= ZIO_COMPRESS_FUNCTIONS) {
100*d0b3ecdcSMartin Matuska errx(1, "invalid compression type: %d",
101*d0b3ecdcSMartin Matuska drrw->drr_compressiontype);
102*d0b3ecdcSMartin Matuska }
103*d0b3ecdcSMartin Matuska break;
104*d0b3ecdcSMartin Matuska
105*d0b3ecdcSMartin Matuska default:
106*d0b3ecdcSMartin Matuska break;
107*d0b3ecdcSMartin Matuska }
108*d0b3ecdcSMartin Matuska
109*d0b3ecdcSMartin Matuska return (D_OK);
110*d0b3ecdcSMartin Matuska }
111*d0b3ecdcSMartin Matuska
112*d0b3ecdcSMartin Matuska chain_step_t
serial_validate_records(void)113*d0b3ecdcSMartin Matuska serial_validate_records(void)
114*d0b3ecdcSMartin Matuska {
115*d0b3ecdcSMartin Matuska int context_ix = next_context++ % MAX_VALIDATIONS;
116*d0b3ecdcSMartin Matuska validate_context_t *context = &contexts[context_ix];
117*d0b3ecdcSMartin Matuska context->nesting = 0;
118*d0b3ecdcSMartin Matuska
119*d0b3ecdcSMartin Matuska chain_step_t step = {
120*d0b3ecdcSMartin Matuska .cs_type = CS_SERIAL,
121*d0b3ecdcSMartin Matuska .cs_in_size = sizeof (drr_packet_t),
122*d0b3ecdcSMartin Matuska .cs_out_size = sizeof (drr_packet_t),
123*d0b3ecdcSMartin Matuska .cs_context = context,
124*d0b3ecdcSMartin Matuska .cs_serial = {
125*d0b3ecdcSMartin Matuska .process = (zc_serial_process_f *)chain_validate_records,
126*d0b3ecdcSMartin Matuska }
127*d0b3ecdcSMartin Matuska };
128*d0b3ecdcSMartin Matuska return (step);
129*d0b3ecdcSMartin Matuska }
130