1148382Spjd/*-
2148382Spjd * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3148382Spjd * All rights reserved.
4148382Spjd *
5148382Spjd * Redistribution and use in source and binary forms, with or without
6148382Spjd * modification, are permitted provided that the following conditions
7148382Spjd * are met:
8148382Spjd * 1. Redistributions of source code must retain the above copyright
9148382Spjd *    notice, this list of conditions and the following disclaimer.
10148382Spjd * 2. Redistributions in binary form must reproduce the above copyright
11148382Spjd *    notice, this list of conditions and the following disclaimer in the
12148382Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14148382Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15148382Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16148382Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148382Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18148382Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148382Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148382Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148382Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148382Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23148382Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24148382Spjd * SUCH DAMAGE.
25148382Spjd */
26148382Spjd
27154473Spjd#include <sys/cdefs.h>
28154473Spjd__FBSDID("$FreeBSD$");
29154473Spjd
30148382Spjd#include <sys/param.h>
31148382Spjd#include <sys/bio.h>
32148382Spjd#include <sys/kernel.h>
33148382Spjd#include <sys/limits.h>
34148382Spjd#include <sys/malloc.h>
35148382Spjd#include <sys/queue.h>
36148382Spjd#include <sys/sysctl.h>
37148382Spjd#include <sys/systm.h>
38148382Spjd
39148382Spjd#include <geom/geom.h>
40148382Spjd
41148382Spjd
42148382Spjd#define	G_ZERO_CLASS_NAME	"ZERO"
43148382Spjd
44254936Smavstatic int	g_zero_clear_sysctl(SYSCTL_HANDLER_ARGS);
45254936Smav
46148382SpjdSYSCTL_DECL(_kern_geom);
47227309Sedstatic SYSCTL_NODE(_kern_geom, OID_AUTO, zero, CTLFLAG_RW, 0,
48227309Sed    "GEOM_ZERO stuff");
49153251Spjdstatic int g_zero_clear = 1;
50254936SmavSYSCTL_PROC(_kern_geom_zero, OID_AUTO, clear, CTLTYPE_INT|CTLFLAG_RW,
51254936Smav    &g_zero_clear, 0, g_zero_clear_sysctl, "I", "Clear read data buffer");
52153251Spjdstatic int g_zero_byte = 0;
53153251SpjdSYSCTL_INT(_kern_geom_zero, OID_AUTO, byte, CTLFLAG_RW, &g_zero_byte, 0,
54153251Spjd    "Byte (octet) value to clear the buffers with");
55148382Spjd
56254936Smavstatic struct g_provider *gpp;
57254936Smav
58254936Smavstatic int
59254936Smavg_zero_clear_sysctl(SYSCTL_HANDLER_ARGS)
60254936Smav{
61254936Smav	int error;
62254936Smav
63254936Smav	error = sysctl_handle_int(oidp, &g_zero_clear, 0, req);
64254936Smav	if (error != 0 || req->newptr == NULL)
65254936Smav		return (error);
66254936Smav	if (gpp == NULL)
67254936Smav		return (ENXIO);
68254936Smav	if (g_zero_clear)
69254936Smav		gpp->flags &= ~G_PF_ACCEPT_UNMAPPED;
70254936Smav	else
71254936Smav		gpp->flags |= G_PF_ACCEPT_UNMAPPED;
72254936Smav	return (0);
73254936Smav}
74254936Smav
75148382Spjdstatic void
76148382Spjdg_zero_start(struct bio *bp)
77148382Spjd{
78148382Spjd	int error = ENXIO;
79148382Spjd
80148382Spjd	switch (bp->bio_cmd) {
81148382Spjd	case BIO_READ:
82254936Smav		if (g_zero_clear && (bp->bio_flags & BIO_UNMAPPED) == 0)
83153251Spjd			memset(bp->bio_data, g_zero_byte, bp->bio_length);
84148382Spjd		/* FALLTHROUGH */
85148382Spjd	case BIO_DELETE:
86148382Spjd	case BIO_WRITE:
87148382Spjd		bp->bio_completed = bp->bio_length;
88148382Spjd		error = 0;
89148382Spjd		break;
90148382Spjd	case BIO_GETATTR:
91148382Spjd	default:
92148382Spjd		error = EOPNOTSUPP;
93148382Spjd		break;
94148382Spjd	}
95148382Spjd	g_io_deliver(bp, error);
96148382Spjd}
97148382Spjd
98148382Spjdstatic void
99148382Spjdg_zero_init(struct g_class *mp)
100148382Spjd{
101148382Spjd	struct g_geom *gp;
102148382Spjd	struct g_provider *pp;
103148382Spjd
104148382Spjd	g_topology_assert();
105148382Spjd	gp = g_new_geomf(mp, "gzero");
106148382Spjd	gp->start = g_zero_start;
107148382Spjd	gp->access = g_std_access;
108254936Smav	gpp = pp = g_new_providerf(gp, "%s", gp->name);
109260385Sscottl	pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
110254936Smav	if (!g_zero_clear)
111254936Smav		pp->flags |= G_PF_ACCEPT_UNMAPPED;
112148382Spjd	pp->mediasize = 1152921504606846976LLU;
113148382Spjd	pp->sectorsize = 512;
114148382Spjd	g_error_provider(pp, 0);
115148382Spjd}
116148382Spjd
117148382Spjdstatic int
118148382Spjdg_zero_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused,
119148382Spjd    struct g_geom *gp)
120148382Spjd{
121148382Spjd	struct g_provider *pp;
122148382Spjd
123148382Spjd	g_topology_assert();
124148382Spjd	if (gp == NULL)
125148382Spjd		return (0);
126148382Spjd	pp = LIST_FIRST(&gp->provider);
127148382Spjd	if (pp == NULL)
128148382Spjd		return (0);
129148382Spjd	if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)
130148382Spjd		return (EBUSY);
131254936Smav	gpp = NULL;
132148382Spjd	g_wither_geom(gp, ENXIO);
133207877Sjh	return (0);
134148382Spjd}
135148382Spjd
136148382Spjdstatic struct g_class g_zero_class = {
137148382Spjd	.name = G_ZERO_CLASS_NAME,
138148382Spjd	.version = G_VERSION,
139148382Spjd	.init = g_zero_init,
140148382Spjd	.destroy_geom = g_zero_destroy_geom
141148382Spjd};
142148382Spjd
143148382SpjdDECLARE_GEOM_CLASS(g_zero_class, g_zero);
144