xref: /freebsd/sys/geom/zoned/g_zoned.c (revision 48efb6c4eb9febc1c8c50d13a794e9165af71930)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2026 voidanix <voidanix@FreeBSD.org>
5  */
6 
7 /*
8  * GEOM_ZONED presents a plain (non-zoned) provider to the rest of the system
9  * as a host-managed zoned block device. The medium is divided into equal
10  * sequential-write-required zones. This GEOM class tracks a write pointer per
11  * zone and answers BIO_ZONE management commands similarly to a real ZBC/ZAC
12  * drive would.
13  *
14  * Persistence:
15  *   - The provider's last sector holds a metadata block, written by the
16  *     userland "create" command. The kernel tastes it on every provider
17  *     arrival and re-creates the zoned device automatically.
18  *   - The sectors just before it hold the per-zone state (condition + write
19  *     pointer). That table is read at taste time and rewritten lazily.
20  *     Zone-state changes, zone-management commands included, only mark the
21  *     table dirty; BIO_FLUSH is what commits them, mirroring a drive whose
22  *     zone state is volatile until a cache flush. Changes since the last
23  *     flush may be rolled back by an unclean shutdown.
24  */
25 
26 #define	EXTERR_CATEGORY	EXTERR_CAT_GEOMZONED
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bio.h>
31 #include <sys/disk_zone.h>
32 #include <sys/endian.h>
33 #include <sys/exterrvar.h>
34 #include <sys/kernel.h>
35 #include <sys/lock.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/mutex.h>
39 #include <sys/sbuf.h>
40 #include <sys/sysctl.h>
41 
42 #include <geom/geom.h>
43 #include <geom/geom_dbg.h>
44 #include <geom/zoned/g_zoned.h>
45 
46 FEATURE(geom_zoned, "GEOM Zoned Storage Medium emulation");
47 
48 static MALLOC_DEFINE(M_ZONED, "zoned_data", "GEOM_ZONED Data");
49 
50 SYSCTL_DECL(_kern_geom);
51 static SYSCTL_NODE(_kern_geom, OID_AUTO, zoned, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
52     "GEOM_ZONED stuff");
53 static u_int g_zoned_debug = 0;
54 SYSCTL_UINT(_kern_geom_zoned, OID_AUTO, debug, CTLFLAG_RW, &g_zoned_debug, 0,
55     "Debug level");
56 
57 #define	G_ZONED_EXTERR(bp, error, ...)	({				\
58 	(bp)->bio_flags |= BIO_EXTERR;					\
59 	EXTERROR_KE(&(bp)->bio_exterr, (error), __VA_ARGS__);		\
60 })
61 
62 static g_access_t g_zoned_access;
63 static g_ctl_req_t g_zoned_config;
64 static g_ctl_destroy_geom_t g_zoned_destroy_geom;
65 static g_dumpconf_t g_zoned_dumpconf;
66 static g_orphan_t g_zoned_orphan;
67 static g_provgone_t g_zoned_providergone;
68 static g_resize_t g_zoned_resize;
69 static g_start_t g_zoned_start;
70 static g_taste_t g_zoned_taste;
71 
72 static struct g_class g_zoned_class = {
73 	.name = G_ZONED_CLASS_NAME,
74 	.version = G_VERSION,
75 	.ctlreq = g_zoned_config,
76 	.destroy_geom = g_zoned_destroy_geom,
77 	.taste = g_zoned_taste,
78 	.access = g_zoned_access,
79 	.dumpconf = g_zoned_dumpconf,
80 	.orphan = g_zoned_orphan,
81 	.providergone = g_zoned_providergone,
82 	.resize = g_zoned_resize,
83 	.spoiled = g_zoned_orphan,
84 	.start = g_zoned_start,
85 };
86 
87 /*
88  * Index of the zone that contains the given LBA. Caller must have range-checked
89  * the LBA against sc_maxlba.
90  */
91 static __inline uint32_t
g_zoned_zoneno(struct g_zoned_softc * sc,uint64_t lba)92 g_zoned_zoneno(struct g_zoned_softc *sc, uint64_t lba)
93 {
94 
95 	return ((uint32_t)(lba / sc->sc_zonesecs));
96 }
97 
98 static bool
g_zoned_is_conv(const struct g_zoned_softc * sc,uint32_t zno)99 g_zoned_is_conv(const struct g_zoned_softc *sc, uint32_t zno)
100 {
101 	const struct g_zoned_convrange *cr;
102 	uint32_t i;
103 
104 	for (i = 0; i < sc->sc_nconv; i++) {
105 		cr = &sc->sc_conv[i];
106 		if (zno >= cr->cr_first && zno - cr->cr_first < cr->cr_count)
107 			return (true);
108 	}
109 	return (false);
110 }
111 
112 /*
113  * Extend the dirty zone range to cover zone zno, so the next BIO_FLUSH
114  * writes its table entry out. Must be called with sc_lock held.
115  */
116 static void
g_zoned_mark_dirty(struct g_zoned_softc * sc,uint32_t zno)117 g_zoned_mark_dirty(struct g_zoned_softc *sc, uint32_t zno)
118 {
119 
120 	mtx_assert(&sc->sc_lock, MA_OWNED);
121 
122 	if (!sc->sc_dirty) {
123 		sc->sc_dirty = true;
124 		sc->sc_dirtylo = sc->sc_dirtyhi = zno;
125 	} else {
126 		if (zno < sc->sc_dirtylo)
127 			sc->sc_dirtylo = zno;
128 		if (zno > sc->sc_dirtyhi)
129 			sc->sc_dirtyhi = zno;
130 	}
131 }
132 
133 static bool
g_zoned_cond_is_open(uint8_t cond)134 g_zoned_cond_is_open(uint8_t cond)
135 {
136 
137 	return (cond == DISK_ZONE_COND_IMPLICIT_OPEN ||
138 	    cond == DISK_ZONE_COND_EXPLICIT_OPEN);
139 }
140 
141 /*
142  * Put a zone into a new condition, maintaining the count of open
143  * zones. Must be called with sc_lock held.
144  */
145 static void
g_zoned_set_cond(struct g_zoned_softc * sc,struct disk_zone_rep_entry * z,uint8_t cond)146 g_zoned_set_cond(struct g_zoned_softc *sc, struct disk_zone_rep_entry *z,
147     uint8_t cond)
148 {
149 	bool is_open, want_open;
150 
151 	mtx_assert(&sc->sc_lock, MA_OWNED);
152 
153 	is_open = g_zoned_cond_is_open(z->zone_condition);
154 	want_open = g_zoned_cond_is_open(cond);
155 	if (!is_open && want_open)
156 		sc->sc_nopen++;
157 	else if (is_open && !want_open)
158 		sc->sc_nopen--;
159 	z->zone_condition = cond;
160 }
161 
162 /*
163  * Make room to open one more zone under the open-zones limit by implicitly
164  * closing the lowest-numbered implicitly-open zone, similarly to a real drive.
165  */
166 static bool
g_zoned_open_room(struct g_zoned_softc * sc)167 g_zoned_open_room(struct g_zoned_softc *sc)
168 {
169 	struct disk_zone_rep_entry *z;
170 	uint32_t i;
171 
172 	mtx_assert(&sc->sc_lock, MA_OWNED);
173 
174 	if (sc->sc_maxopen == 0 || sc->sc_nopen < sc->sc_maxopen)
175 		return (true);
176 	for (i = 0; i < sc->sc_nzones; i++) {
177 		z = &sc->sc_zones[i];
178 		if (z->zone_condition == DISK_ZONE_COND_IMPLICIT_OPEN) {
179 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_CLOSED);
180 			g_zoned_mark_dirty(sc, i);
181 			return (true);
182 		}
183 	}
184 	return (false);
185 }
186 
187 /*
188  * Put every zone into its pure state, with the type coming from the
189  * metadata-defined conventional ranges.
190  */
191 static void
g_zoned_reset_zones(struct g_zoned_softc * sc)192 g_zoned_reset_zones(struct g_zoned_softc *sc)
193 {
194 	struct disk_zone_rep_entry *z;
195 	uint32_t i;
196 
197 	sc->sc_nopen = 0;
198 	for (i = 0; i < sc->sc_nzones; i++) {
199 		z = &sc->sc_zones[i];
200 		z->zone_start_lba = (uint64_t)i * sc->sc_zonesecs;
201 		z->zone_length = sc->sc_zonesecs;
202 		z->zone_flags = 0;
203 		if (g_zoned_is_conv(sc, i)) {
204 			z->zone_type = DISK_ZONE_TYPE_CONVENTIONAL;
205 			z->zone_condition = DISK_ZONE_COND_NOT_WP;
206 			/* Conventional zones have no write pointer. */
207 			z->write_pointer_lba = G_ZONED_WP_NONE_LBA;
208 		} else {
209 			z->zone_type = DISK_ZONE_TYPE_SEQ_REQUIRED;
210 			z->zone_condition = DISK_ZONE_COND_EMPTY;
211 			z->write_pointer_lba = z->zone_start_lba;
212 		}
213 	}
214 }
215 
216 /*
217  * Mark the whole table (header included) dirty so that the first BIO_FLUSH
218  * writes it out.
219  */
220 static void
g_zoned_dirty_table(struct g_zoned_softc * sc)221 g_zoned_dirty_table(struct g_zoned_softc *sc)
222 {
223 
224 	sc->sc_dirty = true;
225 	sc->sc_hdrdirty = true;
226 	sc->sc_dirtylo = 0;
227 	sc->sc_dirtyhi = sc->sc_nzones - 1;
228 }
229 
230 /*
231  * Read the existing persistent zone table from the provider into the live zone
232  * array, otherwise initialise an empty one if no valid table is present.
233  */
234 static void
g_zoned_load_table(struct g_zoned_softc * sc,struct g_consumer * cp)235 g_zoned_load_table(struct g_zoned_softc *sc, struct g_consumer *cp)
236 {
237 	struct g_zoned_table_hdr th;
238 	struct disk_zone_rep_entry *z;
239 	u_char *buf;
240 	off_t off, resid, chunk;
241 	uint32_t i, n, zno;
242 	int error;
243 	bool valid;
244 
245 	g_topology_assert();
246 	g_topology_unlock();
247 
248 	valid = false;
249 	buf = g_read_data(cp, sc->sc_taboff, sc->sc_secsize, &error);
250 	if (buf != NULL) {
251 		zoned_table_hdr_decode(buf, &th);
252 		valid = memcmp(th.th_magic, G_ZONED_TABLE_MAGIC,
253 		    sizeof(G_ZONED_TABLE_MAGIC)) == 0 &&
254 		    th.th_version == G_ZONED_VERSION &&
255 		    th.th_nzones == sc->sc_nzones;
256 		g_free(buf);
257 	}
258 
259 	zno = 0;
260 	off = sc->sc_taboff + sc->sc_secsize;
261 	resid = (off_t)(sc->sc_tabsecs - 1) * sc->sc_secsize;
262 	while (valid && resid > 0) {
263 		chunk = MIN(resid, (off_t)maxphys);
264 		chunk -= chunk % sc->sc_secsize;
265 		if (chunk == 0)
266 			chunk = sc->sc_secsize;
267 		buf = g_read_data(cp, off, chunk, &error);
268 		if (buf == NULL) {
269 			valid = false;
270 			break;
271 		}
272 		n = MIN((uint32_t)(chunk / G_ZONED_ENTRY_SIZE),
273 		    sc->sc_nzones - zno);
274 		for (i = 0; i < n; i++)
275 			g_zoned_entry_decode(buf + i * G_ZONED_ENTRY_SIZE,
276 			    &sc->sc_zones[zno + i],
277 			    (uint64_t)(zno + i) * sc->sc_zonesecs);
278 		g_free(buf);
279 		zno += n;
280 		off += chunk;
281 		resid -= chunk;
282 	}
283 
284 	g_topology_lock();
285 
286 	if (!valid) {
287 		G_ZONED_DEBUG(1, "No valid zone table on %s; initialising.",
288 		    cp->provider->name);
289 		g_zoned_reset_zones(sc);
290 		g_zoned_dirty_table(sc);
291 		return;
292 	}
293 
294 	for (i = 0; i < sc->sc_nzones; i++) {
295 		z = &sc->sc_zones[i];
296 		z->zone_start_lba = (uint64_t)i * sc->sc_zonesecs;
297 		z->zone_length = sc->sc_zonesecs;
298 		/* The metadata dictates zone types, not the table. */
299 		if (g_zoned_is_conv(sc, i)) {
300 			z->zone_type = DISK_ZONE_TYPE_CONVENTIONAL;
301 			z->zone_condition = DISK_ZONE_COND_NOT_WP;
302 			z->write_pointer_lba = G_ZONED_WP_NONE_LBA;
303 			continue;
304 		}
305 		z->zone_type = DISK_ZONE_TYPE_SEQ_REQUIRED;
306 		/* Guard against a corrupt write pointer. */
307 		if (z->write_pointer_lba < z->zone_start_lba ||
308 		    z->write_pointer_lba >
309 		    z->zone_start_lba + z->zone_length) {
310 			z->write_pointer_lba = z->zone_start_lba;
311 			z->zone_condition = DISK_ZONE_COND_EMPTY;
312 		}
313 	}
314 	sc->sc_nopen = 0;
315 	for (i = 0; i < sc->sc_nzones; i++)
316 		if (g_zoned_cond_is_open(sc->sc_zones[i].zone_condition))
317 			sc->sc_nopen++;
318 	G_ZONED_DEBUG(1, "Restored zone table from %s.", cp->provider->name);
319 }
320 
321 /*
322  * "Flush the dirty table sectors, then forward the cache flush" thing. We
323  * allocate one of those per BIO_FLUSH that finds dirty state to commit.
324  */
325 struct g_zoned_flush {
326 	struct bio *fl_orig;	  /* Original BIO_FLUSH. */
327 	struct g_consumer *fl_cp; /* Where to send the I/O. */
328 	struct g_zoned_softc *fl_sc;
329 	u_char *fl_buf;		  /* Snapshot of dirty sectors. */
330 	off_t fl_off;		  /* Disk offset of first sector. */
331 	off_t fl_total;		  /* Bytes to write. */
332 	off_t fl_done;		  /* Bytes written so far. */
333 	u_int fl_secsize;
334 	/* Dirty state the snapshot took: to put back if the write fails. */
335 	uint32_t fl_dirtylo;
336 	uint32_t fl_dirtyhi;
337 	bool fl_hdrdirty;
338 };
339 
340 static void g_zoned_flush_step(struct g_zoned_flush *fc);
341 
342 static void
g_zoned_flush_final(struct bio * bp)343 g_zoned_flush_final(struct bio *bp)
344 {
345 	struct g_zoned_flush *fc = bp->bio_caller1;
346 	struct bio *orig = fc->fl_orig;
347 	int error = bp->bio_error;
348 
349 	g_destroy_bio(bp);
350 	g_free(fc->fl_buf);
351 	g_free(fc);
352 	g_io_deliver(orig, error);
353 }
354 
355 static void
g_zoned_flush_write_done(struct bio * bp)356 g_zoned_flush_write_done(struct bio *bp)
357 {
358 	struct g_zoned_flush *fc = bp->bio_caller1;
359 	int error = bp->bio_error;
360 
361 	g_destroy_bio(bp);
362 	if (error != 0) {
363 		struct g_zoned_softc *sc = fc->fl_sc;
364 
365 		G_ZONED_DEBUG(0, "Zone table write failed (error=%d).", error);
366 		/*
367 		 * Nothing reached the medium, thus the state the snapshot
368 		 * cleared is still only in memory.  Mark it dirty again,
369 		 * widening whatever has been dirtied since, so that the next
370 		 * flush tries once more instead of leaving the table stale.
371 		 */
372 		mtx_lock(&sc->sc_lock);
373 		g_zoned_mark_dirty(sc, fc->fl_dirtylo);
374 		g_zoned_mark_dirty(sc, fc->fl_dirtyhi);
375 		sc->sc_hdrdirty |= fc->fl_hdrdirty;
376 		mtx_unlock(&sc->sc_lock);
377 		g_free(fc->fl_buf);
378 		g_io_deliver(fc->fl_orig, error);
379 		g_free(fc);
380 		return;
381 	}
382 	g_zoned_flush_step(fc);
383 }
384 
385 static void
g_zoned_flush_step(struct g_zoned_flush * fc)386 g_zoned_flush_step(struct g_zoned_flush *fc)
387 {
388 	struct bio *cbp;
389 	off_t chunk;
390 
391 	if (fc->fl_done < fc->fl_total) {
392 		chunk = fc->fl_total - fc->fl_done;
393 		if (chunk > (off_t)maxphys) {
394 			chunk = maxphys;
395 			chunk -= chunk % fc->fl_secsize;
396 		}
397 		cbp = g_alloc_bio();
398 		cbp->bio_cmd = BIO_WRITE;
399 		cbp->bio_offset = fc->fl_off + fc->fl_done;
400 		cbp->bio_data = fc->fl_buf + fc->fl_done;
401 		cbp->bio_length = chunk;
402 		cbp->bio_done = g_zoned_flush_write_done;
403 		cbp->bio_caller1 = fc;
404 		fc->fl_done += chunk;
405 		g_io_request(cbp, fc->fl_cp);
406 		return;
407 	}
408 	/* Table is on its way down; now forward the real cache flush. */
409 	cbp = g_alloc_bio();
410 	cbp->bio_cmd = BIO_FLUSH;
411 	cbp->bio_done = g_zoned_flush_final;
412 	cbp->bio_caller1 = fc;
413 	g_io_request(cbp, fc->fl_cp);
414 }
415 
416 /*
417  * Snapshot the dirty part of the table into a freshly allocated buffer of
418  * whole sectors, encoded in the on-disk format and clear the dirty state.
419  */
420 static u_char *
g_zoned_encode_dirty(struct g_zoned_softc * sc,off_t * offp,off_t * totalp)421 g_zoned_encode_dirty(struct g_zoned_softc *sc, off_t *offp, off_t *totalp)
422 {
423 	struct g_zoned_table_hdr th;
424 	u_char *buf;
425 	off_t total;
426 	uint32_t first, i, limit, seclo, sechi, zpersec;
427 
428 	mtx_assert(&sc->sc_lock, MA_OWNED);
429 
430 	if (!sc->sc_dirty)
431 		return (NULL);
432 	/* Table sector 0 holds the header; entries start at sector 1. */
433 	zpersec = sc->sc_secsize / G_ZONED_ENTRY_SIZE;
434 	seclo = sc->sc_hdrdirty ? 0 : 1 + sc->sc_dirtylo / zpersec;
435 	sechi = 1 + sc->sc_dirtyhi / zpersec;
436 	total = (off_t)(sechi - seclo + 1) * sc->sc_secsize;
437 	buf = g_malloc(total, M_NOWAIT | M_ZERO);
438 	if (buf == NULL)
439 		return (NULL);
440 	if (seclo == 0) {
441 		memset(&th, 0, sizeof(th));
442 		memcpy(th.th_magic, G_ZONED_TABLE_MAGIC,
443 		    sizeof(G_ZONED_TABLE_MAGIC));
444 		th.th_version = G_ZONED_VERSION;
445 		th.th_nzones = sc->sc_nzones;
446 		zoned_table_hdr_encode(&th, buf);
447 	}
448 	/* Encode every entry falling into the sectors being written. */
449 	first = (seclo == 0) ? 0 : (seclo - 1) * zpersec;
450 	limit = MIN(sc->sc_nzones, sechi * zpersec);
451 	for (i = first; i < limit; i++)
452 		g_zoned_entry_encode(&sc->sc_zones[i], buf +
453 		    (seclo == 0 ? sc->sc_secsize : 0) +
454 		    (off_t)(i - first) * G_ZONED_ENTRY_SIZE);
455 	sc->sc_dirty = false;
456 	sc->sc_hdrdirty = false;
457 	*offp = sc->sc_taboff + (off_t)seclo * sc->sc_secsize;
458 	*totalp = total;
459 	return (buf);
460 }
461 
462 /*
463  * Attempt commiting the dirty zone-table state for BIO_FLUSH. Returns true
464  * if it took ownership of bp i.e. an async chain is running or the flush has
465  * failed, false if the caller should forward the flush normally.
466  */
467 static bool
g_zoned_flush_begin(struct g_zoned_softc * sc,struct g_geom * gp,struct bio * bp)468 g_zoned_flush_begin(struct g_zoned_softc *sc, struct g_geom *gp,
469     struct bio *bp)
470 {
471 	struct g_zoned_flush *fc;
472 	struct g_consumer *cp;
473 	u_char *buf;
474 	off_t off, total;
475 	uint32_t dirtylo, dirtyhi;
476 	bool dirty, hdrdirty;
477 
478 	cp = LIST_FIRST(&gp->consumer);
479 	/* Persistence is not possible without write access; just forward. */
480 	if (cp->acw == 0)
481 		return (false);
482 
483 	fc = g_malloc(sizeof(*fc), M_NOWAIT);
484 
485 	mtx_lock(&sc->sc_lock);
486 	dirty = sc->sc_dirty;
487 	dirtylo = sc->sc_dirtylo;
488 	dirtyhi = sc->sc_dirtyhi;
489 	hdrdirty = sc->sc_hdrdirty;
490 	/* Leave the state dirty for the next flush if nothing can carry it. */
491 	buf = (fc != NULL) ? g_zoned_encode_dirty(sc, &off, &total) : NULL;
492 	mtx_unlock(&sc->sc_lock);
493 	if (buf == NULL) {
494 		g_free(fc);
495 		/* Nothing to commit, so the flush stands on its own. */
496 		if (!dirty)
497 			return (false);
498 		/*
499 		 * The table stays in memory, thus this flush cannot claim it
500 		 * reached the medium.  Say so, rather than forwarding a flush
501 		 * that commits none of the state the caller is flushing for.
502 		 */
503 		G_ZONED_DEBUG(0, "No memory to commit the zone table;"
504 		    " failing the flush.");
505 		g_io_deliver(bp, G_ZONED_EXTERR(bp, ENOMEM,
506 		    "No memory to commit the zone table."));
507 		return (true);
508 	}
509 
510 	fc->fl_dirtylo = dirtylo;
511 	fc->fl_dirtyhi = dirtyhi;
512 	fc->fl_hdrdirty = hdrdirty;
513 	fc->fl_orig = bp;
514 	fc->fl_cp = cp;
515 	fc->fl_sc = sc;
516 	fc->fl_buf = buf;
517 	fc->fl_off = off;
518 	fc->fl_total = total;
519 	fc->fl_done = 0;
520 	fc->fl_secsize = sc->sc_secsize;
521 	g_zoned_flush_step(fc);
522 	return (true);
523 }
524 
525 /*
526  * Best-effort, synchronous commit of the dirty zone-table state, for the
527  * destroy path where no further BIO_FLUSH will arrive. A failure means the
528  * on-disk table stays as of the last flush.
529  */
530 static void
g_zoned_flush_sync(struct g_zoned_softc * sc,struct g_consumer * cp)531 g_zoned_flush_sync(struct g_zoned_softc *sc, struct g_consumer *cp)
532 {
533 	u_char *buf;
534 	off_t chunk, done, off, total;
535 	int error;
536 
537 	g_topology_assert();
538 
539 	/* A provider that went away takes the table's location with it. */
540 	if (cp == NULL || cp->provider == NULL || cp->provider->error != 0)
541 		return;
542 	mtx_lock(&sc->sc_lock);
543 	buf = g_zoned_encode_dirty(sc, &off, &total);
544 	mtx_unlock(&sc->sc_lock);
545 	if (buf == NULL)
546 		return;
547 	g_topology_unlock();
548 	error = 0;
549 	for (done = 0; done < total; done += chunk) {
550 		chunk = MIN(total - done, (off_t)maxphys);
551 		chunk -= chunk % sc->sc_secsize;
552 		if (chunk == 0)
553 			chunk = sc->sc_secsize;
554 		error = g_write_data(cp, off + done, buf + done, chunk);
555 		if (error != 0)
556 			break;
557 	}
558 	if (error == 0)
559 		error = g_io_flush(cp);
560 	if (error != 0)
561 		G_ZONED_DEBUG(0,
562 		    "Final zone table write on %s failed (error=%d).",
563 		    cp->provider->name, error);
564 	g_free(buf);
565 	g_topology_lock();
566 }
567 
568 /*
569  * Test a zone against a REPORT ZONES reporting option (DISK_ZONE_REP_*).
570  */
571 static bool
g_zoned_rep_match(const struct disk_zone_rep_entry * z,uint8_t rep_option)572 g_zoned_rep_match(const struct disk_zone_rep_entry *z, uint8_t rep_option)
573 {
574 
575 	switch (rep_option) {
576 	case DISK_ZONE_REP_ALL:
577 		return (true);
578 	case DISK_ZONE_REP_EMPTY:
579 		return (z->zone_condition == DISK_ZONE_COND_EMPTY);
580 	case DISK_ZONE_REP_IMP_OPEN:
581 		return (z->zone_condition == DISK_ZONE_COND_IMPLICIT_OPEN);
582 	case DISK_ZONE_REP_EXP_OPEN:
583 		return (z->zone_condition == DISK_ZONE_COND_EXPLICIT_OPEN);
584 	case DISK_ZONE_REP_CLOSED:
585 		return (z->zone_condition == DISK_ZONE_COND_CLOSED);
586 	case DISK_ZONE_REP_FULL:
587 		return (z->zone_condition == DISK_ZONE_COND_FULL);
588 	case DISK_ZONE_REP_READONLY:
589 		return (z->zone_condition == DISK_ZONE_COND_READONLY);
590 	case DISK_ZONE_REP_OFFLINE:
591 		return (z->zone_condition == DISK_ZONE_COND_OFFLINE);
592 	case DISK_ZONE_REP_RWP:
593 		return ((z->zone_flags & DISK_ZONE_FLAG_RESET) != 0);
594 	case DISK_ZONE_REP_NON_SEQ:
595 		return ((z->zone_flags & DISK_ZONE_FLAG_NON_SEQ) != 0);
596 	case DISK_ZONE_REP_NON_WP:
597 		return (z->zone_condition == DISK_ZONE_COND_NOT_WP);
598 	default:
599 		return (false);
600 	}
601 }
602 
603 static bool
g_zoned_rep_option_valid(uint8_t rep_option)604 g_zoned_rep_option_valid(uint8_t rep_option)
605 {
606 
607 	return (rep_option <= DISK_ZONE_REP_OFFLINE ||
608 	    rep_option == DISK_ZONE_REP_RWP ||
609 	    rep_option == DISK_ZONE_REP_NON_SEQ ||
610 	    rep_option == DISK_ZONE_REP_NON_WP);
611 }
612 
613 /*
614  * Best-effort BIO_DELETE of just-reset zones, so that backing stores can
615  * reclaim the space, similarly to real drives de-allocating a reset zone.
616  */
617 struct g_zoned_punch {
618 	struct bio	*pu_orig;	/* Original BIO_ZONE. */
619 	u_int		 pu_pending;	/* Outstanding deletes + 1. */
620 };
621 
622 static void
g_zoned_punch_rele(struct g_zoned_punch * pc)623 g_zoned_punch_rele(struct g_zoned_punch *pc)
624 {
625 
626 	if (atomic_fetchadd_int(&pc->pu_pending, -1) == 1) {
627 		g_io_deliver(pc->pu_orig, 0);
628 		g_free(pc);
629 	}
630 }
631 
632 static void
g_zoned_punch_done(struct bio * bp)633 g_zoned_punch_done(struct bio *bp)
634 {
635 	struct g_zoned_punch *pc = bp->bio_caller1;
636 
637 	g_destroy_bio(bp);
638 	g_zoned_punch_rele(pc);
639 }
640 
641 static void
g_zoned_punch_queue(struct g_zoned_softc * sc,struct bio_queue_head * queue,const struct disk_zone_rep_entry * z)642 g_zoned_punch_queue(struct g_zoned_softc *sc, struct bio_queue_head *queue,
643     const struct disk_zone_rep_entry *z)
644 {
645 	struct bio *dbp;
646 
647 	mtx_assert(&sc->sc_lock, MA_OWNED);
648 
649 	dbp = g_new_bio();
650 	if (dbp == NULL) {
651 		G_ZONED_DEBUG(1, "No memory to reclaim zone %ju.",
652 		    (uint64_t)g_zoned_zoneno(sc, z->zone_start_lba));
653 		return;
654 	}
655 	dbp->bio_cmd = BIO_DELETE;
656 	dbp->bio_offset = (off_t)z->zone_start_lba * sc->sc_secsize;
657 	dbp->bio_length = sc->sc_zonesize;
658 	dbp->bio_data = NULL;
659 	bioq_insert_tail(queue, dbp);
660 }
661 
662 static void
g_zoned_punch_drain(struct bio_queue_head * queue)663 g_zoned_punch_drain(struct bio_queue_head *queue)
664 {
665 	struct bio *dbp;
666 
667 	while ((dbp = bioq_takefirst(queue)) != NULL)
668 		g_destroy_bio(dbp);
669 }
670 
671 static void
g_zoned_punch_issue(struct bio * bp,struct g_consumer * cp,struct bio_queue_head * queue)672 g_zoned_punch_issue(struct bio *bp, struct g_consumer *cp,
673     struct bio_queue_head *queue)
674 {
675 	struct g_zoned_punch *pc;
676 	struct bio *dbp;
677 
678 	pc = (bioq_first(queue) != NULL) ? g_malloc(sizeof(*pc), M_NOWAIT) :
679 	    NULL;
680 	if (pc == NULL) {
681 		g_zoned_punch_drain(queue);
682 		g_io_deliver(bp, 0);
683 		return;
684 	}
685 	pc->pu_orig = bp;
686 	pc->pu_pending = 1;
687 	while ((dbp = bioq_takefirst(queue)) != NULL) {
688 		dbp->bio_done = g_zoned_punch_done;
689 		dbp->bio_caller1 = pc;
690 		atomic_add_int(&pc->pu_pending, 1);
691 		g_io_request(dbp, cp);
692 	}
693 	g_zoned_punch_rele(pc);
694 }
695 
696 /*
697  * Emulate BIO_ZONE management commands.
698  */
699 static void
g_zoned_zonecmd(struct bio * bp,struct g_zoned_softc * sc)700 g_zoned_zonecmd(struct bio *bp, struct g_zoned_softc *sc)
701 {
702 	struct disk_zone_args *args = &bp->bio_zone;
703 	uint32_t i, first, limit;
704 
705 	switch (args->zone_cmd) {
706 	case DISK_ZONE_GET_PARAMS: {
707 		struct disk_zone_disk_params *p =
708 		    &args->zone_params.disk_params;
709 
710 		p->zone_mode = DISK_ZONE_MODE_HOST_MANAGED;
711 		p->flags = DISK_ZONE_RZ_SUP | DISK_ZONE_OPEN_SUP |
712 		    DISK_ZONE_CLOSE_SUP | DISK_ZONE_FINISH_SUP |
713 		    DISK_ZONE_RWP_SUP | DISK_ZONE_MAX_SEQ_SET;
714 		if (!sc->sc_rdrestrict)
715 			p->flags |= DISK_ZONE_DISK_URSWRZ;
716 		/* Optimal zone counts are host-aware concepts; leave unset. */
717 		p->optimal_seq_zones = 0;
718 		p->optimal_nonseq_zones = 0;
719 		p->max_seq_zones = (sc->sc_maxopen != 0) ? sc->sc_maxopen :
720 		    G_ZONED_SEQ_UNLIMITED;
721 		g_io_deliver(bp, 0);
722 		return;
723 	}
724 	case DISK_ZONE_REPORT_ZONES: {
725 		struct disk_zone_report *rep = &args->zone_params.report;
726 		uint32_t filled, zno;
727 
728 		if (!g_zoned_rep_option_valid(rep->rep_options)) {
729 			g_io_deliver(bp, G_ZONED_EXTERR(bp, EINVAL,
730 			    "Unsupported reporting option.  opt=%ju",
731 			    (uint64_t)rep->rep_options));
732 			return;
733 		}
734 
735 		mtx_lock(&sc->sc_lock);
736 		sc->sc_zonecmds++;
737 		rep->header.same = (sc->sc_convzones == 0 ||
738 		    sc->sc_convzones == sc->sc_nzones) ?
739 		    DISK_ZONE_SAME_ALL_SAME : DISK_ZONE_SAME_TYPES_DIFFERENT;
740 		rep->header.maximum_lba = sc->sc_maxlba - 1;
741 
742 		if (rep->starting_id >= sc->sc_maxlba)
743 			zno = sc->sc_nzones;
744 		else
745 			zno = g_zoned_zoneno(sc, rep->starting_id);
746 
747 		rep->entries_available = 0;
748 		filled = 0;
749 		for (; zno < sc->sc_nzones; zno++) {
750 			if (!g_zoned_rep_match(&sc->sc_zones[zno],
751 			    rep->rep_options))
752 				continue;
753 			rep->entries_available++;
754 			if (filled < rep->entries_allocated &&
755 			    rep->entries != NULL)
756 				rep->entries[filled++] = sc->sc_zones[zno];
757 		}
758 		rep->entries_filled = filled;
759 		mtx_unlock(&sc->sc_lock);
760 		g_io_deliver(bp, 0);
761 		return;
762 	}
763 	case DISK_ZONE_OPEN:
764 	case DISK_ZONE_CLOSE:
765 	case DISK_ZONE_FINISH:
766 	case DISK_ZONE_RWP: {
767 		struct disk_zone_rwp *rwp = &args->zone_params.rwp;
768 		struct bio_queue_head punchq;
769 		struct g_consumer *cp;
770 		bool all = (rwp->flags & DISK_ZONE_RWP_FLAG_ALL) != 0;
771 		bool punch;
772 
773 		if (all) {
774 			first = 0;
775 			limit = sc->sc_nzones;
776 		} else {
777 			if (rwp->id >= sc->sc_maxlba) {
778 				g_io_deliver(bp, G_ZONED_EXTERR(bp, EINVAL,
779 				    "Zone ID past the last LBA.  id=%ju"
780 				    " maxlba=%ju", (uint64_t)rwp->id,
781 				    (uint64_t)sc->sc_maxlba));
782 				return;
783 			}
784 			if ((rwp->id % sc->sc_zonesecs) != 0) {
785 				g_io_deliver(bp, G_ZONED_EXTERR(bp, EINVAL,
786 				    "Zone ID is not the lowest LBA of a zone."
787 				    "  id=%ju zonesecs=%ju",
788 				    (uint64_t)rwp->id,
789 				    (uint64_t)sc->sc_zonesecs));
790 				return;
791 			}
792 			first = g_zoned_zoneno(sc, rwp->id);
793 			limit = first + 1;
794 		}
795 
796 		/*
797 		 * A reset drops the zone's contents, thus hand them back to the
798 		 * backing store as long as it is open for writing.
799 		 */
800 		cp = LIST_FIRST(&bp->bio_to->geom->consumer);
801 		punch = args->zone_cmd == DISK_ZONE_RWP && cp->acw > 0;
802 		bioq_init(&punchq);
803 
804 		mtx_lock(&sc->sc_lock);
805 		sc->sc_zonecmds++;
806 
807 		/*
808 		 * "Open all" must fit within the open-zone limit.
809 		 */
810 		if (all && args->zone_cmd == DISK_ZONE_OPEN &&
811 		    sc->sc_maxopen != 0) {
812 			uint32_t nclosed = 0;
813 
814 			for (i = 0; i < sc->sc_nzones; i++)
815 				if (sc->sc_zones[i].zone_condition ==
816 				    DISK_ZONE_COND_CLOSED)
817 					nclosed++;
818 			if (sc->sc_nopen + nclosed > sc->sc_maxopen) {
819 				mtx_unlock(&sc->sc_lock);
820 				g_zoned_punch_drain(&punchq);
821 				g_io_deliver(bp, G_ZONED_EXTERR(bp, ENOSPC,
822 				    "Opening all zones exceeds the open-zone"
823 				    " limit.  need=%ju maxopen=%ju",
824 				    (uint64_t)(sc->sc_nopen + nclosed),
825 				    (uint64_t)sc->sc_maxopen));
826 				return;
827 			}
828 		}
829 
830 		for (i = first; i < limit; i++) {
831 			struct disk_zone_rep_entry *z = &sc->sc_zones[i];
832 
833 			/*
834 			 * Conventional zones have no write pointer to manage;
835 			 * "all zones" operations skip them, while explicitly
836 			 * targeting one is the caller's error. The same goes
837 			 * for zones taken readonly or offline.
838 			 */
839 			if (z->zone_type == DISK_ZONE_TYPE_CONVENTIONAL ||
840 			    z->zone_condition == DISK_ZONE_COND_READONLY ||
841 			    z->zone_condition == DISK_ZONE_COND_OFFLINE) {
842 				if (all)
843 					continue;
844 				mtx_unlock(&sc->sc_lock);
845 				g_zoned_punch_drain(&punchq);
846 				g_io_deliver(bp, G_ZONED_EXTERR(bp, EINVAL,
847 				    "Zone has no write pointer to manage."
848 				    "  zone=%ju cond=%ju", (uint64_t)i,
849 				    (uint64_t)z->zone_condition));
850 				return;
851 			}
852 			switch (args->zone_cmd) {
853 			/*
854 			 * Many operations here are no-op, per ZBC-r06.
855 			 */
856 			case DISK_ZONE_OPEN:
857 				if (all) {
858 					if (z->zone_condition !=
859 					    DISK_ZONE_COND_CLOSED)
860 						continue;
861 				} else if (z->zone_condition ==
862 				    DISK_ZONE_COND_FULL ||
863 				    z->zone_condition ==
864 				    DISK_ZONE_COND_EXPLICIT_OPEN)
865 					continue;
866 				if (!g_zoned_cond_is_open(z->zone_condition) &&
867 				    !g_zoned_open_room(sc)) {
868 					mtx_unlock(&sc->sc_lock);
869 					g_zoned_punch_drain(&punchq);
870 					g_io_deliver(bp, G_ZONED_EXTERR(bp,
871 					    ENOSPC, "Open-zone limit reached."
872 					    "  zone=%ju maxopen=%ju",
873 					    (uint64_t)i,
874 					    (uint64_t)sc->sc_maxopen));
875 					return;
876 				}
877 				g_zoned_set_cond(sc, z,
878 				    DISK_ZONE_COND_EXPLICIT_OPEN);
879 				break;
880 			case DISK_ZONE_CLOSE:
881 				if (!g_zoned_cond_is_open(z->zone_condition))
882 					continue;
883 				if (z->write_pointer_lba == z->zone_start_lba)
884 					g_zoned_set_cond(sc, z,
885 					    DISK_ZONE_COND_EMPTY);
886 				else
887 					g_zoned_set_cond(sc, z,
888 					    DISK_ZONE_COND_CLOSED);
889 				break;
890 			case DISK_ZONE_FINISH:
891 				if (all &&
892 				    !g_zoned_cond_is_open(z->zone_condition) &&
893 				    z->zone_condition != DISK_ZONE_COND_CLOSED)
894 					continue;
895 				if (z->zone_condition == DISK_ZONE_COND_FULL)
896 					continue;
897 				z->write_pointer_lba = z->zone_start_lba +
898 				    z->zone_length;
899 				g_zoned_set_cond(sc, z, DISK_ZONE_COND_FULL);
900 				break;
901 			case DISK_ZONE_RWP:
902 				/*
903 				 * Empty zones have nothing to reclaim, but a
904 				 * reset still clears the "reset recommended"
905 				 * bit that a fault may have left on it.
906 				 */
907 				if (z->zone_condition == DISK_ZONE_COND_EMPTY) {
908 					if ((z->zone_flags &
909 					    DISK_ZONE_FLAG_RESET) == 0)
910 						continue;
911 					z->zone_flags &= ~DISK_ZONE_FLAG_RESET;
912 					break;
913 				}
914 				z->write_pointer_lba = z->zone_start_lba;
915 				z->zone_flags &= ~DISK_ZONE_FLAG_RESET;
916 				g_zoned_set_cond(sc, z, DISK_ZONE_COND_EMPTY);
917 				if (punch)
918 					g_zoned_punch_queue(sc, &punchq, z);
919 				break;
920 			}
921 			g_zoned_mark_dirty(sc, i);
922 		}
923 		mtx_unlock(&sc->sc_lock);
924 		if (punch) {
925 			g_zoned_punch_issue(bp, cp, &punchq);
926 			return;
927 		}
928 		g_io_deliver(bp, 0);
929 		return;
930 	}
931 	default:
932 		G_ZONED_LOGREQLVL(1, bp, "Unsupported zone command %u.",
933 		    args->zone_cmd);
934 		g_io_deliver(bp, G_ZONED_EXTERR(bp, EOPNOTSUPP,
935 		    "Unsupported zone command.  cmd=%ju",
936 		    (uint64_t)args->zone_cmd));
937 		return;
938 	}
939 }
940 
941 /*
942  * Validate a write against the zone model, advancing the write pointer.
943  */
944 static int
g_zoned_write_check(struct g_zoned_softc * sc,struct bio * bp,uint8_t * oldcond)945 g_zoned_write_check(struct g_zoned_softc *sc, struct bio *bp, uint8_t *oldcond)
946 {
947 	struct disk_zone_rep_entry *z;
948 	uint64_t lba, end;
949 	uint32_t i, last, zno;
950 
951 	mtx_assert(&sc->sc_lock, MA_OWNED);
952 
953 	*oldcond = DISK_ZONE_COND_NOT_WP;
954 
955 	lba = bp->bio_offset / sc->sc_secsize;
956 	end = (bp->bio_offset + bp->bio_length) / sc->sc_secsize;
957 	if (end > sc->sc_maxlba)
958 		return (G_ZONED_EXTERR(bp, EIO,
959 		    "Write past the last LBA.  end=%ju maxlba=%ju",
960 		    (uint64_t)end, (uint64_t)sc->sc_maxlba));
961 
962 	zno = g_zoned_zoneno(sc, lba);
963 	z = &sc->sc_zones[zno];
964 
965 	if (z->zone_type == DISK_ZONE_TYPE_CONVENTIONAL) {
966 		/*
967 		 * Conventional zones take writes anywhere and requests may
968 		 * span zone boundaries into other conventional zones.
969 		 */
970 		last = (end > lba) ? g_zoned_zoneno(sc, end - 1) : zno;
971 		for (i = zno; i <= last; i++) {
972 			if (i > zno && sc->sc_zones[i].zone_type !=
973 			    DISK_ZONE_TYPE_CONVENTIONAL) {
974 				G_ZONED_LOGREQLVL(1, bp, "Write crosses from "
975 				    "a conventional into a sequential zone.");
976 				return (G_ZONED_EXTERR(bp, EIO,
977 				    "Write crosses from a conventional into a"
978 				    " sequential zone.  lba=%ju zone=%ju",
979 				    (uint64_t)lba, (uint64_t)i));
980 			}
981 			if (sc->sc_zones[i].zone_condition ==
982 			    DISK_ZONE_COND_READONLY ||
983 			    sc->sc_zones[i].zone_condition ==
984 			    DISK_ZONE_COND_OFFLINE) {
985 				G_ZONED_LOGREQLVL(1, bp,
986 				    "Write to a readonly/offline zone.");
987 				return (G_ZONED_EXTERR(bp, EIO,
988 				    "Write to a readonly or offline zone."
989 				    "  zone=%ju cond=%ju", (uint64_t)i,
990 				    (uint64_t)sc->sc_zones[i].zone_condition));
991 			}
992 		}
993 	} else {
994 		if (z->zone_condition == DISK_ZONE_COND_READONLY ||
995 		    z->zone_condition == DISK_ZONE_COND_OFFLINE) {
996 			G_ZONED_LOGREQLVL(1, bp,
997 			    "Write to a readonly/offline zone.");
998 			return (G_ZONED_EXTERR(bp, EIO,
999 			    "Write to a readonly or offline zone."
1000 			    "  zone=%ju cond=%ju", (uint64_t)zno,
1001 			    (uint64_t)z->zone_condition));
1002 		}
1003 		if (end > z->zone_start_lba + z->zone_length) {
1004 			G_ZONED_LOGREQLVL(1, bp,
1005 			    "Write crosses a zone boundary.");
1006 			return (G_ZONED_EXTERR(bp, EIO,
1007 			    "Write crosses a zone boundary.  end=%ju"
1008 			    " zoneend=%ju", (uint64_t)end,
1009 			    (uint64_t)(z->zone_start_lba + z->zone_length)));
1010 		}
1011 
1012 		/*
1013 		 * Sequential-write-required zones accept writes at the
1014 		 * WP only.
1015 		 */
1016 		if (z->zone_condition == DISK_ZONE_COND_FULL ||
1017 		    lba != z->write_pointer_lba) {
1018 			G_ZONED_LOGREQLVL(1, bp,
1019 			    "Out-of-order write to zone %u (lba %ju, wp %ju).",
1020 			    zno, (uintmax_t)lba,
1021 			    (uintmax_t)z->write_pointer_lba);
1022 			return (G_ZONED_EXTERR(bp, EIO,
1023 			    "Write pointer violation.  lba=%ju wp=%ju",
1024 			    (uint64_t)lba, (uint64_t)z->write_pointer_lba));
1025 		}
1026 
1027 		/*
1028 		 * Implicitly opening one more zone(s) must respect the
1029 		 * open-zone limit; a write that fills the zone outright
1030 		 * never leaves it open.
1031 		 */
1032 		if (!g_zoned_cond_is_open(z->zone_condition) &&
1033 		    end < z->zone_start_lba + z->zone_length &&
1034 		    !g_zoned_open_room(sc)) {
1035 			G_ZONED_LOGREQLVL(1, bp,
1036 			    "Cannot implicitly open zone %u:"
1037 			    " open-zone limit reached.", zno);
1038 			return (G_ZONED_EXTERR(bp, ENOSPC,
1039 			    "Open-zone limit reached.  zone=%ju maxopen=%ju",
1040 			    (uint64_t)zno, (uint64_t)sc->sc_maxopen));
1041 		}
1042 
1043 		*oldcond = z->zone_condition;
1044 		z->write_pointer_lba = end;
1045 		if (z->write_pointer_lba >= z->zone_start_lba + z->zone_length)
1046 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_FULL);
1047 		else if (!g_zoned_cond_is_open(z->zone_condition))
1048 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_IMPLICIT_OPEN);
1049 		g_zoned_mark_dirty(sc, zno);
1050 	}
1051 
1052 	return (0);
1053 }
1054 
1055 /*
1056  * Validate a read against the zone model.  A read may never reach a zone of
1057  * a different type than the one it starts in, nor touch an offline zone,
1058  * whatever URSWRZ says; only spanning several sequential zones and reading
1059  * above the write pointer depend on it.
1060  */
1061 static int
g_zoned_read_check(struct g_zoned_softc * sc,struct bio * bp)1062 g_zoned_read_check(struct g_zoned_softc *sc, struct bio *bp)
1063 {
1064 	struct disk_zone_rep_entry *z;
1065 	uint64_t lba, end;
1066 	uint32_t i, last, zno;
1067 
1068 	mtx_assert(&sc->sc_lock, MA_OWNED);
1069 
1070 	lba = bp->bio_offset / sc->sc_secsize;
1071 	end = (bp->bio_offset + bp->bio_length) / sc->sc_secsize;
1072 	if (end > sc->sc_maxlba)
1073 		return (G_ZONED_EXTERR(bp, EIO,
1074 		    "Read past the last LBA.  end=%ju maxlba=%ju",
1075 		    (uint64_t)end, (uint64_t)sc->sc_maxlba));
1076 
1077 	zno = g_zoned_zoneno(sc, lba);
1078 	z = &sc->sc_zones[zno];
1079 	last = (end > lba) ? g_zoned_zoneno(sc, end - 1) : zno;
1080 
1081 	for (i = zno; i <= last; i++) {
1082 		if (sc->sc_zones[i].zone_condition == DISK_ZONE_COND_OFFLINE) {
1083 			G_ZONED_LOGREQLVL(1, bp, "Read from an offline zone.");
1084 			return (G_ZONED_EXTERR(bp, EIO,
1085 			    "Read from an offline zone.  zone=%ju",
1086 			    (uint64_t)i));
1087 		}
1088 		if (i > zno && sc->sc_zones[i].zone_type != z->zone_type) {
1089 			G_ZONED_LOGREQLVL(1, bp, "Read crosses into a zone of "
1090 			    "a different type.");
1091 			return (G_ZONED_EXTERR(bp, EIO,
1092 			    "Read crosses into a zone of a different type."
1093 			    "  lba=%ju zone=%ju", (uint64_t)lba,
1094 			    (uint64_t)i));
1095 		}
1096 	}
1097 
1098 	if (!sc->sc_rdrestrict || z->zone_type == DISK_ZONE_TYPE_CONVENTIONAL)
1099 		return (0);
1100 
1101 	if (end > z->zone_start_lba + z->zone_length) {
1102 		G_ZONED_LOGREQLVL(1, bp, "Read crosses a zone boundary.");
1103 		return (G_ZONED_EXTERR(bp, EIO,
1104 		    "Read crosses a zone boundary.  end=%ju zoneend=%ju",
1105 		    (uint64_t)end,
1106 		    (uint64_t)(z->zone_start_lba + z->zone_length)));
1107 	}
1108 	if (end > z->write_pointer_lba) {
1109 		G_ZONED_LOGREQLVL(1, bp,
1110 		    "Read above the write pointer of zone %u (lba %ju,"
1111 		    " wp %ju).", zno, (uintmax_t)lba,
1112 		    (uintmax_t)z->write_pointer_lba);
1113 		return (G_ZONED_EXTERR(bp, EIO,
1114 		    "Read above the write pointer.  end=%ju wp=%ju",
1115 		    (uint64_t)end, (uint64_t)z->write_pointer_lba));
1116 	}
1117 	return (0);
1118 }
1119 
1120 /*
1121  * A write whose data never reaches the medium leaves the zone claiming blocks
1122  * that were never written, so retract the optimistic write-pointer advance, as
1123  * long as no later write has moved the pointer further.  The zone rolls back
1124  * to the condition the write found it in.
1125  */
1126 static void
g_zoned_write_undo(struct g_zoned_softc * sc,off_t offset,off_t length,uint8_t oldcond)1127 g_zoned_write_undo(struct g_zoned_softc *sc, off_t offset, off_t length,
1128     uint8_t oldcond)
1129 {
1130 	struct disk_zone_rep_entry *z;
1131 	uint64_t lba, end;
1132 	uint32_t zno;
1133 
1134 	lba = offset / sc->sc_secsize;
1135 	end = (offset + length) / sc->sc_secsize;
1136 
1137 	mtx_lock(&sc->sc_lock);
1138 	zno = g_zoned_zoneno(sc, lba);
1139 	z = &sc->sc_zones[zno];
1140 	if (z->zone_type != DISK_ZONE_TYPE_CONVENTIONAL &&
1141 	    z->write_pointer_lba == end) {
1142 		z->write_pointer_lba = lba;
1143 		g_zoned_set_cond(sc, z, oldcond);
1144 		g_zoned_mark_dirty(sc, zno);
1145 	}
1146 	mtx_unlock(&sc->sc_lock);
1147 }
1148 
1149 static void
g_zoned_write_done(struct bio * cbp)1150 g_zoned_write_done(struct bio *cbp)
1151 {
1152 	struct g_zoned_softc *sc;
1153 	struct bio *pbp;
1154 
1155 	pbp = cbp->bio_parent;
1156 	sc = pbp->bio_to->geom->softc;
1157 	if (cbp->bio_error != 0 && sc != NULL)
1158 		g_zoned_write_undo(sc, cbp->bio_offset, cbp->bio_length,
1159 		    (uint8_t)(uintptr_t)cbp->bio_caller1);
1160 	g_std_done(cbp);
1161 }
1162 
1163 static void
g_zoned_start(struct bio * bp)1164 g_zoned_start(struct bio *bp)
1165 {
1166 	struct g_zoned_softc *sc;
1167 	struct g_geom *gp;
1168 	struct bio *cbp;
1169 	int error;
1170 	uint8_t oldcond = DISK_ZONE_COND_NOT_WP;
1171 
1172 	gp = bp->bio_to->geom;
1173 	sc = gp->softc;
1174 	G_ZONED_LOGREQ(bp, "Request received.");
1175 
1176 	switch (bp->bio_cmd) {
1177 	case BIO_ZONE:
1178 		g_zoned_zonecmd(bp, sc);
1179 		return;
1180 	case BIO_WRITE:
1181 		mtx_lock(&sc->sc_lock);
1182 		error = g_zoned_write_check(sc, bp, &oldcond);
1183 		if (error != 0) {
1184 			mtx_unlock(&sc->sc_lock);
1185 			g_io_deliver(bp, error);
1186 			return;
1187 		}
1188 		sc->sc_writes++;
1189 		sc->sc_wrotebytes += bp->bio_length;
1190 		mtx_unlock(&sc->sc_lock);
1191 		break;
1192 	case BIO_READ:
1193 		mtx_lock(&sc->sc_lock);
1194 		error = g_zoned_read_check(sc, bp);
1195 		if (error != 0) {
1196 			mtx_unlock(&sc->sc_lock);
1197 			g_io_deliver(bp, error);
1198 			return;
1199 		}
1200 		sc->sc_reads++;
1201 		sc->sc_readbytes += bp->bio_length;
1202 		mtx_unlock(&sc->sc_lock);
1203 		break;
1204 	case BIO_FLUSH:
1205 		if (g_zoned_flush_begin(sc, gp, bp))
1206 			return;
1207 		break;
1208 	case BIO_GETATTR:
1209 		/* BIO_DELETE is refused below, don't advertise it. */
1210 		if (g_handleattr_int(bp, "GEOM::candelete", 0))
1211 			return;
1212 		break;
1213 	case BIO_DELETE:
1214 		/*
1215 		 * Zoned device have no unmap; sequential zones are reclaimed by
1216 		 * resetting the write pointer instead.
1217 		 */
1218 		g_io_deliver(bp, G_ZONED_EXTERR(bp, EOPNOTSUPP,
1219 		    "Zoned providers have no unmap; reset the write pointer"
1220 		    " instead."));
1221 		return;
1222 	default:
1223 		break;
1224 	}
1225 
1226 	cbp = g_clone_bio(bp);
1227 	if (cbp == NULL) {
1228 		if (bp->bio_cmd == BIO_WRITE)
1229 			g_zoned_write_undo(sc, bp->bio_offset, bp->bio_length,
1230 			    oldcond);
1231 		g_io_deliver(bp, ENOMEM);
1232 		return;
1233 	}
1234 	if (bp->bio_cmd == BIO_WRITE) {
1235 		cbp->bio_done = g_zoned_write_done;
1236 		cbp->bio_caller1 = (void *)(uintptr_t)oldcond;
1237 	} else
1238 		cbp->bio_done = g_std_done;
1239 	G_ZONED_LOGREQ(cbp, "Sending request.");
1240 	g_io_request(cbp, LIST_FIRST(&gp->consumer));
1241 }
1242 
1243 static int
g_zoned_access(struct g_provider * pp __unused,int dr __unused,int dw __unused,int de __unused)1244 g_zoned_access(struct g_provider *pp __unused, int dr __unused,
1245     int dw __unused, int de __unused)
1246 {
1247 
1248 	return (0);
1249 }
1250 
1251 static struct g_geom *
g_zoned_create(struct g_class * mp,const struct g_zoned_metadata * md,struct g_provider * pp)1252 g_zoned_create(struct g_class *mp, const struct g_zoned_metadata *md,
1253     struct g_provider *pp)
1254 {
1255 	struct g_zoned_softc *sc;
1256 	struct g_geom *gp;
1257 	struct g_provider *newpp;
1258 	struct g_consumer *cp;
1259 	char name[64];
1260 	uint64_t nzones, zonesecs;
1261 	uint32_t i;
1262 	int error;
1263 
1264 	g_topology_assert();
1265 
1266 	nzones = g_zoned_nzones(pp->mediasize, md->md_zonesize, pp->sectorsize);
1267 	zonesecs = md->md_zonesize / pp->sectorsize;
1268 	if (nzones == 0 || zonesecs == 0 || zonesecs > G_ZONED_MAXZONESECS ||
1269 	    (md->md_zonesize % pp->sectorsize) != 0 ||
1270 	    md->md_nconv > G_ZONED_MAXCONV ||
1271 	    (md->md_flags & ~G_ZONED_MD_FLAGSMASK) != 0) {
1272 		G_ZONED_DEBUG(0, "Bogus metadata on %s.", pp->name);
1273 		return (NULL);
1274 	}
1275 	for (i = 0; i < md->md_nconv; i++) {
1276 		if (md->md_conv[i].cr_count == 0 ||
1277 		    md->md_conv[i].cr_first >= nzones ||
1278 		    md->md_conv[i].cr_count >
1279 		    nzones - md->md_conv[i].cr_first) {
1280 			G_ZONED_DEBUG(0,
1281 			    "Bogus conventional zone range on %s.", pp->name);
1282 			return (NULL);
1283 		}
1284 	}
1285 
1286 	snprintf(name, sizeof(name), "%s%s", pp->name, G_ZONED_SUFFIX);
1287 	LIST_FOREACH(gp, &mp->geom, geom) {
1288 		if (strcmp(gp->name, name) == 0) {
1289 			G_ZONED_DEBUG(0, "Device %s already exists.", name);
1290 			return (NULL);
1291 		}
1292 	}
1293 
1294 	gp = g_new_geom(mp, name);
1295 	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
1296 
1297 	sc->sc_id = md->md_id;
1298 	sc->sc_zonesize = md->md_zonesize;
1299 	sc->sc_secsize = pp->sectorsize;
1300 	sc->sc_zonesecs = zonesecs;
1301 	sc->sc_nzones = (uint32_t)nzones;
1302 	sc->sc_maxlba = nzones * zonesecs;
1303 	sc->sc_nconv = md->md_nconv;
1304 	sc->sc_maxopen = md->md_maxopen;
1305 	sc->sc_rdrestrict = (md->md_flags & G_ZONED_MD_RESTRICTED_READS) != 0;
1306 	bcopy(md->md_conv, sc->sc_conv, sizeof(sc->sc_conv));
1307 	/* Count per zone so that overlapping ranges are not double-counted. */
1308 	for (i = 0; i < nzones; i++)
1309 		if (g_zoned_is_conv(sc, i))
1310 			sc->sc_convzones++;
1311 	sc->sc_zones = malloc(nzones * sizeof(*sc->sc_zones), M_ZONED,
1312 	    M_NOWAIT | M_ZERO);
1313 	if (sc->sc_zones == NULL) {
1314 		G_ZONED_DEBUG(0, "Cannot allocate a %u zone table for %s.",
1315 		    sc->sc_nzones, pp->name);
1316 		g_free(sc);
1317 		g_destroy_geom(gp);
1318 		return (NULL);
1319 	}
1320 	sc->sc_tabsecs = 1 +
1321 	    howmany(nzones * G_ZONED_ENTRY_SIZE, pp->sectorsize);
1322 	sc->sc_taboff = (pp->mediasize - pp->sectorsize) -
1323 	    (off_t)sc->sc_tabsecs * pp->sectorsize;
1324 	g_zoned_reset_zones(sc);
1325 	mtx_init(&sc->sc_lock, "gzoned lock", NULL, MTX_DEF);
1326 	gp->softc = sc;
1327 
1328 	newpp = g_new_providerf(gp, "%s", gp->name);
1329 	newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
1330 	newpp->mediasize = (off_t)nzones * md->md_zonesize;
1331 	newpp->sectorsize = pp->sectorsize;
1332 	newpp->stripesize = pp->stripesize;
1333 	newpp->stripeoffset = pp->stripeoffset;
1334 
1335 	cp = g_new_consumer(gp);
1336 	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
1337 	error = g_attach(cp, pp);
1338 	if (error != 0) {
1339 		G_ZONED_DEBUG(0, "Cannot attach to provider %s.", pp->name);
1340 		goto fail;
1341 	}
1342 	/* Hold the backing provider open as long as the device exists. */
1343 	error = g_access(cp, 1, 1, 1);
1344 	if (error != 0) {
1345 		G_ZONED_DEBUG(0, "Cannot access provider %s.", pp->name);
1346 		goto fail;
1347 	}
1348 
1349 	/* Restore the persistent zone state or initialise an empty table. */
1350 	g_zoned_load_table(sc, cp);
1351 
1352 	newpp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
1353 	g_error_provider(newpp, 0);
1354 	G_ZONED_DEBUG(0, "Device %s created (%u zones of %jd bytes).",
1355 	    gp->name, sc->sc_nzones, (intmax_t)sc->sc_zonesize);
1356 	return (gp);
1357 fail:
1358 	if (cp->provider != NULL)
1359 		g_detach(cp);
1360 	g_destroy_consumer(cp);
1361 	g_destroy_provider(newpp);
1362 	g_destroy_geom(gp);
1363 	return (NULL);
1364 }
1365 
1366 static int
g_zoned_read_metadata(struct g_consumer * cp,struct g_zoned_metadata * md)1367 g_zoned_read_metadata(struct g_consumer *cp, struct g_zoned_metadata *md)
1368 {
1369 	struct g_provider *pp;
1370 	u_char *buf;
1371 	int error;
1372 
1373 	g_topology_assert();
1374 
1375 	error = g_access(cp, 1, 0, 0);
1376 	if (error != 0)
1377 		return (error);
1378 	pp = cp->provider;
1379 	g_topology_unlock();
1380 	buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
1381 	    &error);
1382 	g_topology_lock();
1383 	g_access(cp, -1, 0, 0);
1384 	if (buf == NULL)
1385 		return (error);
1386 	zoned_metadata_decode(buf, md);
1387 	g_free(buf);
1388 	return (0);
1389 }
1390 
1391 static struct g_geom *
g_zoned_taste(struct g_class * mp,struct g_provider * pp,int flags __unused)1392 g_zoned_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
1393 {
1394 	struct g_zoned_metadata md;
1395 	struct g_zoned_softc *sc;
1396 	struct g_consumer *cp;
1397 	struct g_geom *gp;
1398 	int error;
1399 
1400 	g_topology_assert();
1401 
1402 	/* Skip providers that are already open for writing. */
1403 	if (pp->acw > 0)
1404 		return (NULL);
1405 
1406 	G_ZONED_DEBUG(3, "Tasting %s.", pp->name);
1407 
1408 	gp = g_new_geom(mp, "zoned:taste");
1409 	cp = g_new_consumer(gp);
1410 	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
1411 	error = g_attach(cp, pp);
1412 	if (error == 0) {
1413 		error = g_zoned_read_metadata(cp, &md);
1414 		g_detach(cp);
1415 	}
1416 	g_destroy_consumer(cp);
1417 	g_destroy_geom(gp);
1418 	if (error != 0)
1419 		return (NULL);
1420 
1421 	if (strcmp(md.md_magic, G_ZONED_MAGIC) != 0)
1422 		return (NULL);
1423 	if (md.md_version > G_ZONED_VERSION) {
1424 		printf("geom_zoned.ko module is too old to handle %s.\n",
1425 		    pp->name);
1426 		return (NULL);
1427 	}
1428 	if (md.md_provsize != (uint64_t)pp->mediasize)
1429 		return (NULL);
1430 	if (md.md_sectorsize != pp->sectorsize)
1431 		return (NULL);
1432 
1433 	/* Already running? */
1434 	LIST_FOREACH(gp, &mp->geom, geom) {
1435 		sc = gp->softc;
1436 		if (sc != NULL && sc->sc_id == md.md_id)
1437 			return (NULL);
1438 	}
1439 
1440 	gp = g_zoned_create(mp, &md, pp);
1441 	if (gp == NULL)
1442 		G_ZONED_DEBUG(0, "Cannot create zoned device on %s.",
1443 		    pp->name);
1444 	return (gp);
1445 }
1446 
1447 static int
g_zoned_destroy(struct g_geom * gp,boolean_t force)1448 g_zoned_destroy(struct g_geom *gp, boolean_t force)
1449 {
1450 	struct g_zoned_softc *sc;
1451 	struct g_provider *pp;
1452 
1453 	g_topology_assert();
1454 	sc = gp->softc;
1455 	if (sc == NULL)
1456 		return (ENXIO);
1457 	/* An orphaned provider and a stop request can both land here. */
1458 	if ((gp->flags & G_GEOM_WITHER) != 0)
1459 		return (ENXIO);
1460 	pp = LIST_FIRST(&gp->provider);
1461 	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
1462 		if (force) {
1463 			G_ZONED_DEBUG(0,
1464 			    "Device %s is still open, so it "
1465 			    "can't be definitely removed.",
1466 			    pp->name);
1467 		} else {
1468 			G_ZONED_DEBUG(1, "Device %s is still open (r%dw%de%d).",
1469 			    pp->name, pp->acr, pp->acw, pp->ace);
1470 			return (EBUSY);
1471 		}
1472 	} else {
1473 		G_ZONED_DEBUG(0, "Device %s removed.", gp->name);
1474 	}
1475 
1476 	/* Commit unflushed zone state to survive the stop. */
1477 	g_zoned_flush_sync(sc, LIST_FIRST(&gp->consumer));
1478 
1479 	/*
1480 	 * Give up the reference taken when the device was created, so that
1481 	 * withering can reap the consumer.
1482 	 */
1483 	g_wither_geom_close(gp, ENXIO);
1484 	return (0);
1485 }
1486 
1487 static int
g_zoned_destroy_geom(struct gctl_req * req __unused,struct g_class * mp __unused,struct g_geom * gp)1488 g_zoned_destroy_geom(struct gctl_req *req __unused,
1489     struct g_class *mp __unused, struct g_geom *gp)
1490 {
1491 
1492 	return (g_zoned_destroy(gp, 0));
1493 }
1494 
1495 static void
g_zoned_orphan(struct g_consumer * cp)1496 g_zoned_orphan(struct g_consumer *cp)
1497 {
1498 
1499 	g_topology_assert();
1500 	g_zoned_destroy(cp->geom, 1);
1501 }
1502 
1503 /*
1504  * The metadata and zone table live at the tail of the backing provider, which
1505  * has just moved: neither the on-disk state nor the zone layout can stay
1506  * consistent, so tear the device down. Unflushed zone state is discarded rather
1507  * than written to what is no longer the table's location.
1508  */
1509 static void
g_zoned_resize(struct g_consumer * cp)1510 g_zoned_resize(struct g_consumer *cp)
1511 {
1512 	struct g_zoned_softc *sc;
1513 
1514 	g_topology_assert();
1515 
1516 	sc = cp->geom->softc;
1517 	if (sc == NULL)
1518 		return;
1519 	G_ZONED_DEBUG(0, "Provider %s resized; destroying %s.",
1520 	    cp->provider->name, cp->geom->name);
1521 	mtx_lock(&sc->sc_lock);
1522 	sc->sc_dirty = false;
1523 	sc->sc_hdrdirty = false;
1524 	mtx_unlock(&sc->sc_lock);
1525 	g_zoned_destroy(cp->geom, 1);
1526 }
1527 
1528 static void
g_zoned_providergone(struct g_provider * pp)1529 g_zoned_providergone(struct g_provider *pp)
1530 {
1531 	struct g_geom *gp = pp->geom;
1532 	struct g_zoned_softc *sc = gp->softc;
1533 
1534 	gp->softc = NULL;
1535 	free(sc->sc_zones, M_ZONED);
1536 	mtx_destroy(&sc->sc_lock);
1537 	g_free(sc);
1538 }
1539 
1540 static struct g_geom *
g_zoned_find_geom(struct g_class * mp,const char * name)1541 g_zoned_find_geom(struct g_class *mp, const char *name)
1542 {
1543 	struct g_geom *gp;
1544 
1545 	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1546 		name += strlen(_PATH_DEV);
1547 
1548 	LIST_FOREACH(gp, &mp->geom, geom) {
1549 		if (gp->softc != NULL && strcmp(gp->name, name) == 0)
1550 			return (gp);
1551 	}
1552 	return (NULL);
1553 }
1554 
1555 static void
g_zoned_ctl_create(struct gctl_req * req,struct g_class * mp)1556 g_zoned_ctl_create(struct gctl_req *req, struct g_class *mp)
1557 {
1558 	struct g_zoned_metadata md;
1559 	struct g_provider *pp;
1560 	struct g_consumer *cp;
1561 	struct g_geom *gp;
1562 	const char *name;
1563 	u_char *sector, *buf;
1564 	int *nargs, error, len;
1565 
1566 	g_topology_assert();
1567 
1568 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1569 	if (nargs == NULL) {
1570 		gctl_error(req, "No '%s' argument.", "nargs");
1571 		return;
1572 	}
1573 	if (*nargs != 1) {
1574 		gctl_error(req, "Missing device.");
1575 		return;
1576 	}
1577 	name = gctl_get_asciiparam(req, "arg0");
1578 	if (name == NULL) {
1579 		gctl_error(req, "No 'arg0' argument.");
1580 		return;
1581 	}
1582 	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
1583 		name += strlen(_PATH_DEV);
1584 	pp = g_provider_by_name(name);
1585 	if (pp == NULL) {
1586 		gctl_error(req, "No such provider: %s.", name);
1587 		return;
1588 	}
1589 	sector = gctl_get_param(req, "metadata", &len);
1590 	if (sector == NULL) {
1591 		gctl_error(req, "No '%s' argument.", "metadata");
1592 		return;
1593 	}
1594 	if (len < (int)sizeof(struct g_zoned_metadata) ||
1595 	    len > (int)pp->sectorsize) {
1596 		gctl_error(req, "Invalid '%s' argument.", "metadata");
1597 		return;
1598 	}
1599 
1600 	/*
1601 	 * The geometry was measured in userland, before the request reached
1602 	 * the topology lock, so make sure the provider still matches it.
1603 	 */
1604 	zoned_metadata_decode(sector, &md);
1605 	if (memcmp(md.md_magic, G_ZONED_MAGIC, sizeof(G_ZONED_MAGIC)) != 0 ||
1606 	    md.md_version != G_ZONED_VERSION ||
1607 	    md.md_provsize != (uint64_t)pp->mediasize ||
1608 	    md.md_sectorsize != pp->sectorsize) {
1609 		gctl_error(req, "Invalid metadata for %s.", name);
1610 		return;
1611 	}
1612 
1613 	gp = g_zoned_create(mp, &md, pp);
1614 	if (gp == NULL) {
1615 		gctl_error(req, "Cannot create a zoned device on %s.", name);
1616 		return;
1617 	}
1618 
1619 	/* The tail sector is ours now; pad the metadata out to fill it. */
1620 	cp = LIST_FIRST(&gp->consumer);
1621 	buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1622 	memcpy(buf, sector, len);
1623 	g_topology_unlock();
1624 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, buf,
1625 	    pp->sectorsize);
1626 	if (error == 0)
1627 		error = g_io_flush(cp);
1628 	g_topology_lock();
1629 	g_free(buf);
1630 	if (error != 0) {
1631 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
1632 		    name, error);
1633 		(void)g_zoned_destroy(gp, 1);
1634 	}
1635 }
1636 
1637 static void
g_zoned_ctl_destroy(struct gctl_req * req,struct g_class * mp)1638 g_zoned_ctl_destroy(struct gctl_req *req, struct g_class *mp)
1639 {
1640 	struct g_geom *gp;
1641 	const char *name;
1642 	char param[16];
1643 	int *force, *nargs, error, i;
1644 
1645 	g_topology_assert();
1646 
1647 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1648 	if (nargs == NULL) {
1649 		gctl_error(req, "No '%s' argument.", "nargs");
1650 		return;
1651 	}
1652 	if (*nargs <= 0) {
1653 		gctl_error(req, "Missing device(s).");
1654 		return;
1655 	}
1656 	force = gctl_get_paraml(req, "force", sizeof(*force));
1657 	if (force == NULL) {
1658 		gctl_error(req, "No '%s' argument.", "force");
1659 		return;
1660 	}
1661 
1662 	for (i = 0; i < *nargs; i++) {
1663 		snprintf(param, sizeof(param), "arg%d", i);
1664 		name = gctl_get_asciiparam(req, param);
1665 		if (name == NULL) {
1666 			gctl_error(req, "No 'arg%d' argument.", i);
1667 			return;
1668 		}
1669 		gp = g_zoned_find_geom(mp, name);
1670 		if (gp == NULL) {
1671 			gctl_error(req, "No such device: %s.", name);
1672 			return;
1673 		}
1674 		error = g_zoned_destroy(gp, *force);
1675 		if (error != 0) {
1676 			gctl_error(req, "Cannot destroy device %s (error=%d).",
1677 			    gp->name, error);
1678 			return;
1679 		}
1680 	}
1681 }
1682 
1683 /*
1684  * Fault injection: force a zone readonly or offline and flag it as needing a
1685  * write-pointer reset, or clear the fault again. The state persists through the
1686  * zone table.
1687  */
1688 static void
g_zoned_ctl_fault(struct gctl_req * req,struct g_class * mp)1689 g_zoned_ctl_fault(struct gctl_req *req, struct g_class *mp)
1690 {
1691 	struct g_zoned_softc *sc;
1692 	struct g_geom *gp;
1693 	struct disk_zone_rep_entry *z;
1694 	const char *name, *state;
1695 	intmax_t *zone;
1696 	uint32_t zno;
1697 
1698 	g_topology_assert();
1699 
1700 	name = gctl_get_asciiparam(req, "arg0");
1701 	if (name == NULL) {
1702 		gctl_error(req, "Missing device.");
1703 		return;
1704 	}
1705 	zone = gctl_get_paraml(req, "zone", sizeof(*zone));
1706 	if (zone == NULL) {
1707 		gctl_error(req, "No '%s' argument.", "zone");
1708 		return;
1709 	}
1710 	state = gctl_get_asciiparam(req, "state");
1711 	if (state == NULL) {
1712 		gctl_error(req, "No '%s' argument.", "state");
1713 		return;
1714 	}
1715 	gp = g_zoned_find_geom(mp, name);
1716 	if (gp == NULL) {
1717 		gctl_error(req, "No such device: %s.", name);
1718 		return;
1719 	}
1720 	sc = gp->softc;
1721 	if (*zone < 0 || (uintmax_t)*zone >= sc->sc_nzones) {
1722 		gctl_error(req, "Zone %jd out of range.", *zone);
1723 		return;
1724 	}
1725 	zno = (uint32_t)*zone;
1726 
1727 	mtx_lock(&sc->sc_lock);
1728 	z = &sc->sc_zones[zno];
1729 	if (strcmp(state, "ro") == 0 || strcmp(state, "readonly") == 0)
1730 		g_zoned_set_cond(sc, z, DISK_ZONE_COND_READONLY);
1731 	else if (strcmp(state, "offline") == 0)
1732 		g_zoned_set_cond(sc, z, DISK_ZONE_COND_OFFLINE);
1733 	else if (strcmp(state, "reset") == 0)
1734 		z->zone_flags |= DISK_ZONE_FLAG_RESET;
1735 	else if (strcmp(state, "clear") == 0) {
1736 		/* Reobtain the normal condition from the write pointer. */
1737 		z->zone_flags &= ~DISK_ZONE_FLAG_RESET;
1738 		if (z->zone_type == DISK_ZONE_TYPE_CONVENTIONAL)
1739 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_NOT_WP);
1740 		else if (z->write_pointer_lba == z->zone_start_lba)
1741 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_EMPTY);
1742 		else if (z->write_pointer_lba ==
1743 		    z->zone_start_lba + z->zone_length)
1744 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_FULL);
1745 		else
1746 			g_zoned_set_cond(sc, z, DISK_ZONE_COND_CLOSED);
1747 	} else {
1748 		mtx_unlock(&sc->sc_lock);
1749 		gctl_error(req, "Invalid state '%s'.", state);
1750 		return;
1751 	}
1752 	g_zoned_mark_dirty(sc, zno);
1753 	mtx_unlock(&sc->sc_lock);
1754 }
1755 
1756 static void
g_zoned_config(struct gctl_req * req,struct g_class * mp,const char * verb)1757 g_zoned_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1758 {
1759 	uint32_t *version;
1760 
1761 	g_topology_assert();
1762 
1763 	version = gctl_get_paraml(req, "version", sizeof(*version));
1764 	if (version == NULL) {
1765 		gctl_error(req, "No '%s' argument.", "version");
1766 		return;
1767 	}
1768 	if (*version != G_ZONED_VERSION) {
1769 		gctl_error(req, "Userland and kernel parts are out of sync.");
1770 		return;
1771 	}
1772 
1773 	if (strcmp(verb, "create") == 0) {
1774 		g_zoned_ctl_create(req, mp);
1775 		return;
1776 	}
1777 	if (strcmp(verb, "destroy") == 0 || strcmp(verb, "stop") == 0) {
1778 		g_zoned_ctl_destroy(req, mp);
1779 		return;
1780 	}
1781 	if (strcmp(verb, "fault") == 0) {
1782 		g_zoned_ctl_fault(req, mp);
1783 		return;
1784 	}
1785 	gctl_error(req, "Unknown verb.");
1786 }
1787 
1788 static void
g_zoned_dumpconf(struct sbuf * sb,const char * indent,struct g_geom * gp,struct g_consumer * cp,struct g_provider * pp)1789 g_zoned_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1790     struct g_consumer *cp, struct g_provider *pp)
1791 {
1792 	struct g_zoned_softc *sc;
1793 
1794 	if (pp != NULL || cp != NULL)
1795 		return;
1796 	sc = gp->softc;
1797 	sbuf_printf(sb, "%s<ZoneSize>%jd</ZoneSize>\n", indent,
1798 	    (intmax_t)sc->sc_zonesize);
1799 	sbuf_printf(sb, "%s<Zones>%u</Zones>\n", indent, sc->sc_nzones);
1800 	sbuf_printf(sb, "%s<ConventionalZones>%u</ConventionalZones>\n",
1801 	    indent, sc->sc_convzones);
1802 	sbuf_printf(sb, "%s<Mode>Host Managed</Mode>\n", indent);
1803 	sbuf_printf(sb, "%s<UnrestrictedReads>%s</UnrestrictedReads>\n", indent,
1804 	    sc->sc_rdrestrict ? "No" : "Yes");
1805 	sbuf_printf(sb, "%s<MaxOpenZones>%u</MaxOpenZones>\n", indent,
1806 	    sc->sc_maxopen);
1807 	sbuf_printf(sb, "%s<OpenZones>%u</OpenZones>\n", indent, sc->sc_nopen);
1808 	sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
1809 	sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
1810 	sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
1811 	    sc->sc_readbytes);
1812 	sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
1813 	    sc->sc_wrotebytes);
1814 	sbuf_printf(sb, "%s<ZoneCommands>%ju</ZoneCommands>\n", indent,
1815 	    sc->sc_zonecmds);
1816 }
1817 
1818 DECLARE_GEOM_CLASS(g_zoned_class, g_zoned);
1819 MODULE_VERSION(geom_zoned, 0);
1820