xref: /freebsd/sys/contrib/openzfs/cmd/zstream/zstream_drop_record.c (revision 2f10ffc003be396f3fc23cd2888023896560252b)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 
13 /*
14  * Copyright 2026 ConnectWise.  All rights reserved.
15  * Use is subject to license terms.
16  */
17 
18 #include <err.h>
19 #include <errno.h>
20 #include <search.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stdtypes.h>
26 #include <sys/zfs_ioctl.h>
27 #include <unistd.h>
28 
29 #include "zstream.h"
30 #include "zstream_modules.h"
31 
32 #define	KEYSIZE 64
33 
34 static disposition_t
chain_drop_records(void * item_in,void * context)35 chain_drop_records(void *item_in, void *context)
36 {
37 	(void) context;
38 	drr_packet_t *item = (drr_packet_t *)item_in;
39 
40 	if (item == NULL)
41 		return (D_OK);
42 
43 	dmu_replay_record_t *drr = &item->dp_drr;
44 	struct drr_write *drrw = &drr->drr_u.drr_write;
45 	struct drr_write_embedded *drrwe = &drr->drr_u.drr_write_embedded;
46 	char key[KEYSIZE];
47 	u_longlong_t object, offset;
48 	const char *record_type;
49 	ENTRY e = {.key = key};
50 
51 	if (drr->drr_type == DRR_WRITE) {
52 		object = drrw->drr_object;
53 		offset = drrw->drr_offset;
54 		record_type = "WRITE";
55 	} else if (drr->drr_type == DRR_WRITE_EMBEDDED) {
56 		object = drrwe->drr_object;
57 		offset = drrwe->drr_offset;
58 		record_type = "WRITE_EMBEDDED";
59 	} else {
60 		return (D_OK);
61 	}
62 
63 	snprintf(key, KEYSIZE, "%llu,%llu", object, offset);
64 	if (hsearch(e, FIND) != NULL) {
65 		if (OPTION_ENABLED(CA_VERBOSE)) {
66 			warnx("dropping %s record for object %llu "
67 			    "offset %llu", record_type, object, offset);
68 		}
69 		set_payload(item, NULL, 0);
70 		return (D_DROP);
71 	}
72 
73 	return (D_OK);
74 }
75 
76 static chain_step_t
serial_drop_records(void)77 serial_drop_records(void)
78 {
79 	chain_step_t step = {
80 		.cs_type = CS_SERIAL,
81 		.cs_in_size = sizeof (drr_packet_t),
82 		.cs_out_size = sizeof (drr_packet_t),
83 		.cs_context = NULL,
84 		.cs_serial = {
85 			.process = chain_drop_records
86 		}
87 	};
88 	return (step);
89 }
90 
91 int
zstream_do_drop_record(int argc,char * argv[])92 zstream_do_drop_record(int argc, char *argv[])
93 {
94 	int c;
95 	chain_attrs_t attrs = {0};
96 
97 	while ((c = getopt(argc, argv, "v")) != -1) {
98 		switch (c) {
99 		case 'v':
100 			ENABLE_OPTION(&attrs, CA_VERBOSE);
101 			break;
102 		case '?':
103 			warnx("invalid option '%c'\n", optopt);
104 			zstream_usage();
105 		}
106 	}
107 
108 	argc -= optind;
109 	argv += optind;
110 
111 	if (argc < 0)
112 		zstream_usage();
113 	if (hcreate(argc) == 0)
114 		errx(1, "hcreate failed");
115 
116 	for (int i = 0; i < argc; i++) {
117 
118 		uint64_t object, offset;
119 		char *obj_str;
120 		char *offset_str;
121 		char *key;
122 		char *end;
123 
124 		obj_str = strsep(&argv[i], ",");
125 		if (argv[i] == NULL)
126 			zstream_usage();
127 		errno = 0;
128 		object = strtoull(obj_str, &end, 0);
129 		if (errno || *end != '\0')
130 			errx(1, "invalid value for object");
131 		offset_str = strsep(&argv[i], ",");
132 		offset = strtoull(offset_str, &end, 0);
133 		if (errno || *end != '\0')
134 			errx(1, "invalid value for offset");
135 
136 		if (asprintf(&key, "%llu,%llu", (u_longlong_t)object,
137 		    (u_longlong_t)offset) < 0) {
138 			err(1, "asprintf");
139 		}
140 		ENTRY e = {.key = key};
141 		ENTRY *p;
142 		p = hsearch(e, ENTER);
143 		if (p == NULL)
144 			errx(1, "hsearch");
145 		p->data = (void *)(intptr_t)B_TRUE;
146 	}
147 
148 	ENABLE_OPTION(&attrs, CA_FORBID_DEDUP);
149 
150 	zstream_chain_t drop_chain = {
151 		STANDARD_INPUT_STACK(NULL),
152 		serial_drop_records(),
153 		STANDARD_OUTPUT_STACK(NULL)
154 	};
155 	zstream_chain_exec(drop_chain, &attrs);
156 
157 	hdestroy();
158 	return (0);
159 }
160