1 /*-
2 * Copyright (c) 2003 Poul-Henning Kamp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The names of the authors may not be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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/cdefs.h>
31 __FBSDID("$FreeBSD: releng/5.2/sys/geom/geom_mirror.c 116196 2003-06-11 06:49:16Z obrien $");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/conf.h>
37 #include <sys/bio.h>
38 #include <sys/malloc.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/libkern.h>
42 #include <sys/endian.h>
43 #include <sys/md5.h>
44 #include <sys/errno.h>
45 #include <geom/geom.h>
46
47 #define MIRROR_MAGIC "GEOM::MIRROR"
48
49 struct g_mirror_softc {
50 off_t mediasize;
51 u_int sectorsize;
52 u_char magic[16];
53 };
54
55
56 static int
57 g_mirror_add(struct g_geom *gp, struct g_provider *pp)
58 {
59 struct g_consumer *cp;
60
61 g_trace(G_T_TOPOLOGY, "g_mirror_add(%s, %s)", gp->name, pp->name);
62 g_topology_assert();
63 cp = g_new_consumer(gp);
64 g_attach(cp, pp);
65 return (0);
66 }
67
68 static void
69 g_mirror_orphan(struct g_consumer *cp)
70 {
71 struct g_geom *gp;
72 int error;
73
74 g_topology_assert();
75 gp = cp->geom;
76 g_access_rel(cp, -cp->acr, -cp->acw, -cp->ace);
77 error = cp->provider->error;
78 g_detach(cp);
79 g_destroy_consumer(cp);
80 if (!LIST_EMPTY(&gp->consumer))
81 return;
82 g_free(gp->softc);
83 g_wither_geom(gp, error);
84 }
85
86 static void
87 g_mirror_done(struct bio *bp)
88 {
89 struct g_geom *gp;
90 struct g_mirror_softc *sc;
91 struct g_consumer *cp;
92
93 gp = bp->bio_to->geom;
94 sc = gp->softc;
95 cp = LIST_NEXT(bp->bio_from, consumer);
96 if (cp == NULL)
97 g_std_done(bp);
98 else
99 g_io_request(bp, cp);
100 }
101
102 static void
103 g_mirror_start(struct bio *bp)
104 {
105 struct g_geom *gp;
106 struct bio *bp2;
107 struct g_mirror_softc *sc;
108
109 gp = bp->bio_to->geom;
110 sc = gp->softc;
111 switch(bp->bio_cmd) {
112 case BIO_READ:
113 bp2 = g_clone_bio(bp);
114 bp2->bio_offset += sc->sectorsize;
115 bp2->bio_done = g_std_done;
116 g_io_request(bp2, LIST_FIRST(&gp->consumer));
117 return;
118 case BIO_WRITE:
119 case BIO_DELETE:
120 bp2 = g_clone_bio(bp);
121 bp2->bio_offset += sc->sectorsize;
122 bp2->bio_done = g_mirror_done;
123 g_io_request(bp2, LIST_FIRST(&gp->consumer));
124 return;
125 default:
126 g_io_deliver(bp, EOPNOTSUPP);
127 return;
128 }
129 }
130
131 static int
132 g_mirror_access(struct g_provider *pp, int dr, int dw, int de)
133 {
134 struct g_geom *gp;
135 struct g_consumer *cp1, *cp2;
136 int error;
137
138 de += dr;
139 de += dw;
140
141 gp = pp->geom;
142 error = ENXIO;
143 LIST_FOREACH(cp1, &gp->consumer, consumer) {
144 error = g_access_rel(cp1, dr, dw, de);
145 if (error) {
146 LIST_FOREACH(cp2, &gp->consumer, consumer) {
147 if (cp2 == cp1)
148 break;
149 g_access_rel(cp2, -dr, -dw, -de);
150 }
151 return (error);
152 }
153 }
154 return (error);
155 }
156
157 static struct g_geom *
158 g_mirror_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
159 {
160 struct g_geom *gp, *gp2;
161 struct g_provider *pp2;
162 struct g_consumer *cp;
163 struct g_mirror_softc *sc;
164 int error;
165 u_int sectorsize;
166 u_char *buf;
167
168 g_trace(G_T_TOPOLOGY, "mirror_taste(%s, %s)", mp->name, pp->name);
169 g_topology_assert();
170 gp = g_new_geomf(mp, "%s.mirror", pp->name);
171
172 gp->start = g_mirror_start;
173 gp->spoiled = g_mirror_orphan;
174 gp->orphan = g_mirror_orphan;
175 gp->access= g_mirror_access;
176 cp = g_new_consumer(gp);
177 g_attach(cp, pp);
178 error = g_access_rel(cp, 1, 0, 0);
179 if (error) {
180 g_detach(cp);
181 g_destroy_consumer(cp);
182 g_destroy_geom(gp);
183 return(NULL);
184 }
185 g_topology_unlock();
186 do {
187 sectorsize = cp->provider->sectorsize;
188 buf = g_read_data(cp, 0, sectorsize, &error);
189 if (buf == NULL || error != 0)
190 break;
191 if (memcmp(buf, MIRROR_MAGIC, strlen(MIRROR_MAGIC)))
192 break;
193 LIST_FOREACH(gp2, &mp->geom, geom) {
194 sc = gp2->softc;
195 if (sc == NULL)
196 continue;
197 if (memcmp(buf + 16, sc->magic, sizeof sc->magic))
198 continue;
199 break;
200 }
201 /* We found somebody else */
202 if (gp2 != NULL) {
203 g_topology_lock();
204 g_mirror_add(gp2, pp);
205 g_topology_unlock();
206 break;
207 }
208 gp->softc = g_malloc(sizeof(struct g_mirror_softc), M_WAITOK);
209 sc = gp->softc;
210 memcpy(sc->magic, buf + 16, sizeof sc->magic);
211 g_topology_lock();
212 pp2 = g_new_providerf(gp, "%s", gp->name);
213 pp2->mediasize = sc->mediasize = pp->mediasize - pp->sectorsize;
214 pp2->sectorsize = sc->sectorsize = pp->sectorsize;
215 g_error_provider(pp2, 0);
216 g_topology_unlock();
217 } while (0);
218 g_topology_lock();
219 if (buf != NULL)
220 g_free(buf);
221 g_access_rel(cp, -1, 0, 0);
222 if (gp->softc != NULL)
223 return (gp);
224 g_detach(cp);
225 g_destroy_consumer(cp);
226 g_destroy_geom(gp);
227 return (NULL);
228 }
229
230 #define MIRROR_CLASS_NAME "MIRROR"
231
232 static struct g_class g_mirror_class = {
233 .name = MIRROR_CLASS_NAME,
234 .taste = g_mirror_taste,
235 };
236
237 DECLARE_GEOM_CLASS(g_mirror_class, g_mirror);
Cache object: 5e9ef6806795c912b2e52ee6a9f6d1f6
|