Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/geom/zero/g_zero.c
103589 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2005 Pawel Jakub Dawidek <[email protected]>
5
* All rights reserved.
6
* Copyright (c) 2025 Mateusz Piotrowski <[email protected]>
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/param.h>
31
#include <sys/bio.h>
32
#include <sys/kernel.h>
33
#include <sys/limits.h>
34
#include <sys/malloc.h>
35
#include <sys/queue.h>
36
#include <sys/sysctl.h>
37
#include <sys/systm.h>
38
#include <sys/uio.h>
39
#include <sys/types.h>
40
41
#include <geom/geom.h>
42
43
#define G_ZERO_CLASS_NAME "ZERO"
44
45
static int g_zero_byte_sysctl(SYSCTL_HANDLER_ARGS);
46
47
SYSCTL_DECL(_kern_geom);
48
static SYSCTL_NODE(_kern_geom, OID_AUTO, zero, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
49
"GEOM_ZERO stuff");
50
static int g_zero_clear = 1;
51
SYSCTL_INT(_kern_geom_zero, OID_AUTO, clear,
52
CTLFLAG_RWTUN, &g_zero_clear, 0,
53
"Clear read data buffer");
54
static int g_zero_byte = 0;
55
static uint8_t g_zero_buffer[PAGE_SIZE];
56
SYSCTL_PROC(_kern_geom_zero, OID_AUTO, byte,
57
CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &g_zero_byte, 0,
58
g_zero_byte_sysctl, "I",
59
"Byte (octet) value to clear the buffers with");
60
61
static struct g_provider *gpp;
62
63
static int
64
g_zero_byte_sysctl(SYSCTL_HANDLER_ARGS)
65
{
66
int error;
67
68
// XXX: Confirm that this is called on module load as well.
69
// XXX: Shouldn't we lock here to avoid changing the byte value if the
70
// driver is in the process of handling I/O?
71
error = sysctl_handle_int(oidp, &g_zero_byte, 0, req);
72
if (error != 0 || req->newptr == NULL)
73
return (error);
74
memset(g_zero_buffer, g_zero_byte, PAGE_SIZE);
75
return (0);
76
}
77
78
static void
79
g_zero_fill_pages(struct bio *bp)
80
{
81
struct iovec aiovec;
82
struct uio auio;
83
size_t length;
84
vm_offset_t offset;
85
86
aiovec.iov_base = g_zero_buffer;
87
aiovec.iov_len = PAGE_SIZE;
88
auio.uio_iov = &aiovec;
89
auio.uio_iovcnt = 1;
90
auio.uio_offset = 0;
91
auio.uio_segflg = UIO_SYSSPACE;
92
auio.uio_rw = UIO_WRITE;
93
auio.uio_td = curthread;
94
95
/*
96
* To handle the unmapped I/O request, we need to fill the pages in the
97
* bp->bio_ma array with the g_zero_byte value. However, instead of
98
* setting every byte individually, we use uiomove_fromphys() to fill a
99
* page at a time with g_zero_buffer.
100
*/
101
bp->bio_resid = bp->bio_length;
102
offset = bp->bio_ma_offset & PAGE_MASK;
103
for (int i = 0; i < bp->bio_ma_n && bp->bio_resid > 0; i++) {
104
length = MIN(PAGE_SIZE - offset, bp->bio_resid);
105
auio.uio_resid = length;
106
107
(void)uiomove_fromphys(&bp->bio_ma[i], offset, length, &auio);
108
109
offset = 0;
110
bp->bio_resid -= length;
111
}
112
}
113
114
115
static void
116
g_zero_start(struct bio *bp)
117
{
118
int error;
119
120
switch (bp->bio_cmd) {
121
case BIO_READ:
122
if (g_zero_clear) {
123
if ((bp->bio_flags & BIO_UNMAPPED) != 0)
124
g_zero_fill_pages(bp);
125
else
126
memset(bp->bio_data, g_zero_byte,
127
bp->bio_length);
128
}
129
/* FALLTHROUGH */
130
case BIO_DELETE:
131
case BIO_WRITE:
132
bp->bio_completed = bp->bio_length;
133
error = 0;
134
break;
135
case BIO_GETATTR:
136
default:
137
error = EOPNOTSUPP;
138
break;
139
}
140
g_io_deliver(bp, error);
141
}
142
143
static void
144
g_zero_init(struct g_class *mp)
145
{
146
struct g_geom *gp;
147
struct g_provider *pp;
148
149
g_topology_assert();
150
gp = g_new_geom(mp, "gzero");
151
gp->start = g_zero_start;
152
gp->access = g_std_access;
153
gpp = pp = g_new_providerf(gp, "%s", gp->name);
154
pp->flags |= G_PF_ACCEPT_UNMAPPED | G_PF_DIRECT_SEND |
155
G_PF_DIRECT_RECEIVE;
156
pp->mediasize = 1152921504606846976LLU;
157
pp->sectorsize = 512;
158
g_error_provider(pp, 0);
159
}
160
161
static int
162
g_zero_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused,
163
struct g_geom *gp)
164
{
165
struct g_provider *pp;
166
167
g_topology_assert();
168
if (gp == NULL)
169
return (0);
170
pp = LIST_FIRST(&gp->provider);
171
if (pp == NULL)
172
return (0);
173
if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)
174
return (EBUSY);
175
gpp = NULL;
176
g_wither_geom(gp, ENXIO);
177
return (0);
178
}
179
180
static struct g_class g_zero_class = {
181
.name = G_ZERO_CLASS_NAME,
182
.version = G_VERSION,
183
.init = g_zero_init,
184
.destroy_geom = g_zero_destroy_geom
185
};
186
187
DECLARE_GEOM_CLASS(g_zero_class, g_zero);
188
MODULE_VERSION(geom_zero, 0);
189
190