xref: /freebsd/sys/geom/raid/tr_raid0.c (revision 89b172238a5dbea197f3bb46fade76edbe13cab5)
1*89b17223SAlexander Motin /*-
2*89b17223SAlexander Motin  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
3*89b17223SAlexander Motin  * All rights reserved.
4*89b17223SAlexander Motin  *
5*89b17223SAlexander Motin  * Redistribution and use in source and binary forms, with or without
6*89b17223SAlexander Motin  * modification, are permitted provided that the following conditions
7*89b17223SAlexander Motin  * are met:
8*89b17223SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
9*89b17223SAlexander Motin  *    notice, this list of conditions and the following disclaimer.
10*89b17223SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
11*89b17223SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
12*89b17223SAlexander Motin  *    documentation and/or other materials provided with the distribution.
13*89b17223SAlexander Motin  *
14*89b17223SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15*89b17223SAlexander Motin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*89b17223SAlexander Motin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*89b17223SAlexander Motin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18*89b17223SAlexander Motin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*89b17223SAlexander Motin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*89b17223SAlexander Motin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*89b17223SAlexander Motin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*89b17223SAlexander Motin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*89b17223SAlexander Motin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*89b17223SAlexander Motin  * SUCH DAMAGE.
25*89b17223SAlexander Motin  */
26*89b17223SAlexander Motin 
27*89b17223SAlexander Motin #include <sys/cdefs.h>
28*89b17223SAlexander Motin __FBSDID("$FreeBSD$");
29*89b17223SAlexander Motin 
30*89b17223SAlexander Motin #include <sys/param.h>
31*89b17223SAlexander Motin #include <sys/bio.h>
32*89b17223SAlexander Motin #include <sys/endian.h>
33*89b17223SAlexander Motin #include <sys/kernel.h>
34*89b17223SAlexander Motin #include <sys/kobj.h>
35*89b17223SAlexander Motin #include <sys/lock.h>
36*89b17223SAlexander Motin #include <sys/malloc.h>
37*89b17223SAlexander Motin #include <sys/mutex.h>
38*89b17223SAlexander Motin #include <sys/systm.h>
39*89b17223SAlexander Motin #include <geom/geom.h>
40*89b17223SAlexander Motin #include "geom/raid/g_raid.h"
41*89b17223SAlexander Motin #include "g_raid_tr_if.h"
42*89b17223SAlexander Motin 
43*89b17223SAlexander Motin static MALLOC_DEFINE(M_TR_RAID0, "tr_raid0_data", "GEOM_RAID RAID0 data");
44*89b17223SAlexander Motin 
45*89b17223SAlexander Motin struct g_raid_tr_raid0_object {
46*89b17223SAlexander Motin 	struct g_raid_tr_object	 trso_base;
47*89b17223SAlexander Motin 	int			 trso_starting;
48*89b17223SAlexander Motin 	int			 trso_stopped;
49*89b17223SAlexander Motin };
50*89b17223SAlexander Motin 
51*89b17223SAlexander Motin static g_raid_tr_taste_t g_raid_tr_taste_raid0;
52*89b17223SAlexander Motin static g_raid_tr_event_t g_raid_tr_event_raid0;
53*89b17223SAlexander Motin static g_raid_tr_start_t g_raid_tr_start_raid0;
54*89b17223SAlexander Motin static g_raid_tr_stop_t g_raid_tr_stop_raid0;
55*89b17223SAlexander Motin static g_raid_tr_iostart_t g_raid_tr_iostart_raid0;
56*89b17223SAlexander Motin static g_raid_tr_iodone_t g_raid_tr_iodone_raid0;
57*89b17223SAlexander Motin static g_raid_tr_kerneldump_t g_raid_tr_kerneldump_raid0;
58*89b17223SAlexander Motin static g_raid_tr_free_t g_raid_tr_free_raid0;
59*89b17223SAlexander Motin 
60*89b17223SAlexander Motin static kobj_method_t g_raid_tr_raid0_methods[] = {
61*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_taste,	g_raid_tr_taste_raid0),
62*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_event,	g_raid_tr_event_raid0),
63*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_start,	g_raid_tr_start_raid0),
64*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_stop,	g_raid_tr_stop_raid0),
65*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_iostart,	g_raid_tr_iostart_raid0),
66*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_iodone,	g_raid_tr_iodone_raid0),
67*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_kerneldump,	g_raid_tr_kerneldump_raid0),
68*89b17223SAlexander Motin 	KOBJMETHOD(g_raid_tr_free,	g_raid_tr_free_raid0),
69*89b17223SAlexander Motin 	{ 0, 0 }
70*89b17223SAlexander Motin };
71*89b17223SAlexander Motin 
72*89b17223SAlexander Motin static struct g_raid_tr_class g_raid_tr_raid0_class = {
73*89b17223SAlexander Motin 	"RAID0",
74*89b17223SAlexander Motin 	g_raid_tr_raid0_methods,
75*89b17223SAlexander Motin 	sizeof(struct g_raid_tr_raid0_object),
76*89b17223SAlexander Motin 	.trc_priority = 100
77*89b17223SAlexander Motin };
78*89b17223SAlexander Motin 
79*89b17223SAlexander Motin static int
80*89b17223SAlexander Motin g_raid_tr_taste_raid0(struct g_raid_tr_object *tr, struct g_raid_volume *volume)
81*89b17223SAlexander Motin {
82*89b17223SAlexander Motin 	struct g_raid_tr_raid0_object *trs;
83*89b17223SAlexander Motin 
84*89b17223SAlexander Motin 	trs = (struct g_raid_tr_raid0_object *)tr;
85*89b17223SAlexander Motin 	if (tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_RAID0 ||
86*89b17223SAlexander Motin 	    tr->tro_volume->v_raid_level_qualifier != G_RAID_VOLUME_RLQ_NONE)
87*89b17223SAlexander Motin 		return (G_RAID_TR_TASTE_FAIL);
88*89b17223SAlexander Motin 	trs->trso_starting = 1;
89*89b17223SAlexander Motin 	return (G_RAID_TR_TASTE_SUCCEED);
90*89b17223SAlexander Motin }
91*89b17223SAlexander Motin 
92*89b17223SAlexander Motin static int
93*89b17223SAlexander Motin g_raid_tr_update_state_raid0(struct g_raid_volume *vol)
94*89b17223SAlexander Motin {
95*89b17223SAlexander Motin 	struct g_raid_tr_raid0_object *trs;
96*89b17223SAlexander Motin 	struct g_raid_softc *sc;
97*89b17223SAlexander Motin 	u_int s;
98*89b17223SAlexander Motin 	int n, f;
99*89b17223SAlexander Motin 
100*89b17223SAlexander Motin 	sc = vol->v_softc;
101*89b17223SAlexander Motin 	trs = (struct g_raid_tr_raid0_object *)vol->v_tr;
102*89b17223SAlexander Motin 	if (trs->trso_stopped)
103*89b17223SAlexander Motin 		s = G_RAID_VOLUME_S_STOPPED;
104*89b17223SAlexander Motin 	else if (trs->trso_starting)
105*89b17223SAlexander Motin 		s = G_RAID_VOLUME_S_STARTING;
106*89b17223SAlexander Motin 	else {
107*89b17223SAlexander Motin 		n = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_ACTIVE);
108*89b17223SAlexander Motin 		f = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_FAILED);
109*89b17223SAlexander Motin 		if (n + f == vol->v_disks_count) {
110*89b17223SAlexander Motin 			if (f == 0)
111*89b17223SAlexander Motin 				s = G_RAID_VOLUME_S_OPTIMAL;
112*89b17223SAlexander Motin 			else
113*89b17223SAlexander Motin 				s = G_RAID_VOLUME_S_SUBOPTIMAL;
114*89b17223SAlexander Motin 		} else
115*89b17223SAlexander Motin 			s = G_RAID_VOLUME_S_BROKEN;
116*89b17223SAlexander Motin 	}
117*89b17223SAlexander Motin 	if (s != vol->v_state) {
118*89b17223SAlexander Motin 		g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ?
119*89b17223SAlexander Motin 		    G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN,
120*89b17223SAlexander Motin 		    G_RAID_EVENT_VOLUME);
121*89b17223SAlexander Motin 		g_raid_change_volume_state(vol, s);
122*89b17223SAlexander Motin 		if (!trs->trso_starting && !trs->trso_stopped)
123*89b17223SAlexander Motin 			g_raid_write_metadata(sc, vol, NULL, NULL);
124*89b17223SAlexander Motin 	}
125*89b17223SAlexander Motin 	return (0);
126*89b17223SAlexander Motin }
127*89b17223SAlexander Motin 
128*89b17223SAlexander Motin static int
129*89b17223SAlexander Motin g_raid_tr_event_raid0(struct g_raid_tr_object *tr,
130*89b17223SAlexander Motin     struct g_raid_subdisk *sd, u_int event)
131*89b17223SAlexander Motin {
132*89b17223SAlexander Motin 	struct g_raid_tr_raid0_object *trs;
133*89b17223SAlexander Motin 	struct g_raid_softc *sc;
134*89b17223SAlexander Motin 	struct g_raid_volume *vol;
135*89b17223SAlexander Motin 	int state;
136*89b17223SAlexander Motin 
137*89b17223SAlexander Motin 	trs = (struct g_raid_tr_raid0_object *)tr;
138*89b17223SAlexander Motin 	vol = tr->tro_volume;
139*89b17223SAlexander Motin 	sc = vol->v_softc;
140*89b17223SAlexander Motin 
141*89b17223SAlexander Motin 	state = sd->sd_state;
142*89b17223SAlexander Motin 	if (state != G_RAID_SUBDISK_S_NONE &&
143*89b17223SAlexander Motin 	    state != G_RAID_SUBDISK_S_FAILED &&
144*89b17223SAlexander Motin 	    state != G_RAID_SUBDISK_S_ACTIVE) {
145*89b17223SAlexander Motin 		G_RAID_DEBUG1(1, sc,
146*89b17223SAlexander Motin 		    "Promote subdisk %s:%d from %s to ACTIVE.",
147*89b17223SAlexander Motin 		    vol->v_name, sd->sd_pos,
148*89b17223SAlexander Motin 		    g_raid_subdisk_state2str(sd->sd_state));
149*89b17223SAlexander Motin 		g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE);
150*89b17223SAlexander Motin 	}
151*89b17223SAlexander Motin 	if (state != sd->sd_state &&
152*89b17223SAlexander Motin 	    !trs->trso_starting && !trs->trso_stopped)
153*89b17223SAlexander Motin 		g_raid_write_metadata(sc, vol, sd, NULL);
154*89b17223SAlexander Motin 	g_raid_tr_update_state_raid0(vol);
155*89b17223SAlexander Motin 	return (0);
156*89b17223SAlexander Motin }
157*89b17223SAlexander Motin 
158*89b17223SAlexander Motin static int
159*89b17223SAlexander Motin g_raid_tr_start_raid0(struct g_raid_tr_object *tr)
160*89b17223SAlexander Motin {
161*89b17223SAlexander Motin 	struct g_raid_tr_raid0_object *trs;
162*89b17223SAlexander Motin 	struct g_raid_volume *vol;
163*89b17223SAlexander Motin 
164*89b17223SAlexander Motin 	trs = (struct g_raid_tr_raid0_object *)tr;
165*89b17223SAlexander Motin 	vol = tr->tro_volume;
166*89b17223SAlexander Motin 	trs->trso_starting = 0;
167*89b17223SAlexander Motin 	g_raid_tr_update_state_raid0(vol);
168*89b17223SAlexander Motin 	return (0);
169*89b17223SAlexander Motin }
170*89b17223SAlexander Motin 
171*89b17223SAlexander Motin static int
172*89b17223SAlexander Motin g_raid_tr_stop_raid0(struct g_raid_tr_object *tr)
173*89b17223SAlexander Motin {
174*89b17223SAlexander Motin 	struct g_raid_tr_raid0_object *trs;
175*89b17223SAlexander Motin 	struct g_raid_volume *vol;
176*89b17223SAlexander Motin 
177*89b17223SAlexander Motin 	trs = (struct g_raid_tr_raid0_object *)tr;
178*89b17223SAlexander Motin 	vol = tr->tro_volume;
179*89b17223SAlexander Motin 	trs->trso_starting = 0;
180*89b17223SAlexander Motin 	trs->trso_stopped = 1;
181*89b17223SAlexander Motin 	g_raid_tr_update_state_raid0(vol);
182*89b17223SAlexander Motin 	return (0);
183*89b17223SAlexander Motin }
184*89b17223SAlexander Motin 
185*89b17223SAlexander Motin static void
186*89b17223SAlexander Motin g_raid_tr_iostart_raid0(struct g_raid_tr_object *tr, struct bio *bp)
187*89b17223SAlexander Motin {
188*89b17223SAlexander Motin 	struct g_raid_volume *vol;
189*89b17223SAlexander Motin 	struct g_raid_subdisk *sd;
190*89b17223SAlexander Motin 	struct bio_queue_head queue;
191*89b17223SAlexander Motin 	struct bio *cbp;
192*89b17223SAlexander Motin 	char *addr;
193*89b17223SAlexander Motin 	off_t offset, start, length, nstripe, remain;
194*89b17223SAlexander Motin 	u_int no, strip_size;
195*89b17223SAlexander Motin 
196*89b17223SAlexander Motin 	vol = tr->tro_volume;
197*89b17223SAlexander Motin 	if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL &&
198*89b17223SAlexander Motin 	    vol->v_state != G_RAID_VOLUME_S_SUBOPTIMAL) {
199*89b17223SAlexander Motin 		g_raid_iodone(bp, EIO);
200*89b17223SAlexander Motin 		return;
201*89b17223SAlexander Motin 	}
202*89b17223SAlexander Motin 	if (bp->bio_cmd == BIO_FLUSH) {
203*89b17223SAlexander Motin 		g_raid_tr_flush_common(tr, bp);
204*89b17223SAlexander Motin 		return;
205*89b17223SAlexander Motin 	}
206*89b17223SAlexander Motin 	addr = bp->bio_data;
207*89b17223SAlexander Motin 	strip_size = vol->v_strip_size;
208*89b17223SAlexander Motin 
209*89b17223SAlexander Motin 	/* Stripe number. */
210*89b17223SAlexander Motin 	nstripe = bp->bio_offset / strip_size;
211*89b17223SAlexander Motin 	/* Start position in stripe. */
212*89b17223SAlexander Motin 	start = bp->bio_offset % strip_size;
213*89b17223SAlexander Motin 	/* Disk number. */
214*89b17223SAlexander Motin 	no = nstripe % vol->v_disks_count;
215*89b17223SAlexander Motin 	/* Stripe start position in disk. */
216*89b17223SAlexander Motin 	offset = (nstripe / vol->v_disks_count) * strip_size;
217*89b17223SAlexander Motin 	/* Length of data to operate. */
218*89b17223SAlexander Motin 	remain = bp->bio_length;
219*89b17223SAlexander Motin 
220*89b17223SAlexander Motin 	bioq_init(&queue);
221*89b17223SAlexander Motin 	do {
222*89b17223SAlexander Motin 		length = MIN(strip_size - start, remain);
223*89b17223SAlexander Motin 		cbp = g_clone_bio(bp);
224*89b17223SAlexander Motin 		if (cbp == NULL)
225*89b17223SAlexander Motin 			goto failure;
226*89b17223SAlexander Motin 		cbp->bio_offset = offset + start;
227*89b17223SAlexander Motin 		cbp->bio_data = addr;
228*89b17223SAlexander Motin 		cbp->bio_length = length;
229*89b17223SAlexander Motin 		cbp->bio_caller1 = &vol->v_subdisks[no];
230*89b17223SAlexander Motin 		bioq_insert_tail(&queue, cbp);
231*89b17223SAlexander Motin 		if (++no >= vol->v_disks_count) {
232*89b17223SAlexander Motin 			no = 0;
233*89b17223SAlexander Motin 			offset += strip_size;
234*89b17223SAlexander Motin 		}
235*89b17223SAlexander Motin 		remain -= length;
236*89b17223SAlexander Motin 		addr += length;
237*89b17223SAlexander Motin 		start = 0;
238*89b17223SAlexander Motin 	} while (remain > 0);
239*89b17223SAlexander Motin 	for (cbp = bioq_first(&queue); cbp != NULL;
240*89b17223SAlexander Motin 	    cbp = bioq_first(&queue)) {
241*89b17223SAlexander Motin 		bioq_remove(&queue, cbp);
242*89b17223SAlexander Motin 		sd = cbp->bio_caller1;
243*89b17223SAlexander Motin 		cbp->bio_caller1 = NULL;
244*89b17223SAlexander Motin 		g_raid_subdisk_iostart(sd, cbp);
245*89b17223SAlexander Motin 	}
246*89b17223SAlexander Motin 	return;
247*89b17223SAlexander Motin failure:
248*89b17223SAlexander Motin 	for (cbp = bioq_first(&queue); cbp != NULL;
249*89b17223SAlexander Motin 	    cbp = bioq_first(&queue)) {
250*89b17223SAlexander Motin 		bioq_remove(&queue, cbp);
251*89b17223SAlexander Motin 		g_destroy_bio(cbp);
252*89b17223SAlexander Motin 	}
253*89b17223SAlexander Motin 	if (bp->bio_error == 0)
254*89b17223SAlexander Motin 		bp->bio_error = ENOMEM;
255*89b17223SAlexander Motin 	g_raid_iodone(bp, bp->bio_error);
256*89b17223SAlexander Motin }
257*89b17223SAlexander Motin 
258*89b17223SAlexander Motin static int
259*89b17223SAlexander Motin g_raid_tr_kerneldump_raid0(struct g_raid_tr_object *tr,
260*89b17223SAlexander Motin     void *virtual, vm_offset_t physical, off_t boffset, size_t blength)
261*89b17223SAlexander Motin {
262*89b17223SAlexander Motin 	struct g_raid_volume *vol;
263*89b17223SAlexander Motin 	char *addr;
264*89b17223SAlexander Motin 	off_t offset, start, length, nstripe, remain;
265*89b17223SAlexander Motin 	u_int no, strip_size;
266*89b17223SAlexander Motin 	int error;
267*89b17223SAlexander Motin 
268*89b17223SAlexander Motin 	vol = tr->tro_volume;
269*89b17223SAlexander Motin 	if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL)
270*89b17223SAlexander Motin 		return (ENXIO);
271*89b17223SAlexander Motin 	addr = virtual;
272*89b17223SAlexander Motin 	strip_size = vol->v_strip_size;
273*89b17223SAlexander Motin 
274*89b17223SAlexander Motin 	/* Stripe number. */
275*89b17223SAlexander Motin 	nstripe = boffset / strip_size;
276*89b17223SAlexander Motin 	/* Start position in stripe. */
277*89b17223SAlexander Motin 	start = boffset % strip_size;
278*89b17223SAlexander Motin 	/* Disk number. */
279*89b17223SAlexander Motin 	no = nstripe % vol->v_disks_count;
280*89b17223SAlexander Motin 	/* Stripe tart position in disk. */
281*89b17223SAlexander Motin 	offset = (nstripe / vol->v_disks_count) * strip_size;
282*89b17223SAlexander Motin 	/* Length of data to operate. */
283*89b17223SAlexander Motin 	remain = blength;
284*89b17223SAlexander Motin 
285*89b17223SAlexander Motin 	do {
286*89b17223SAlexander Motin 		length = MIN(strip_size - start, remain);
287*89b17223SAlexander Motin 		error = g_raid_subdisk_kerneldump(&vol->v_subdisks[no],
288*89b17223SAlexander Motin 		    addr, 0, offset + start, length);
289*89b17223SAlexander Motin 		if (error != 0)
290*89b17223SAlexander Motin 			return (error);
291*89b17223SAlexander Motin 		if (++no >= vol->v_disks_count) {
292*89b17223SAlexander Motin 			no = 0;
293*89b17223SAlexander Motin 			offset += strip_size;
294*89b17223SAlexander Motin 		}
295*89b17223SAlexander Motin 		remain -= length;
296*89b17223SAlexander Motin 		addr += length;
297*89b17223SAlexander Motin 		start = 0;
298*89b17223SAlexander Motin 	} while (remain > 0);
299*89b17223SAlexander Motin 	return (0);
300*89b17223SAlexander Motin }
301*89b17223SAlexander Motin 
302*89b17223SAlexander Motin static void
303*89b17223SAlexander Motin g_raid_tr_iodone_raid0(struct g_raid_tr_object *tr,
304*89b17223SAlexander Motin     struct g_raid_subdisk *sd,struct bio *bp)
305*89b17223SAlexander Motin {
306*89b17223SAlexander Motin 	struct bio *pbp;
307*89b17223SAlexander Motin 
308*89b17223SAlexander Motin 	pbp = bp->bio_parent;
309*89b17223SAlexander Motin 	if (pbp->bio_error == 0)
310*89b17223SAlexander Motin 		pbp->bio_error = bp->bio_error;
311*89b17223SAlexander Motin 	g_destroy_bio(bp);
312*89b17223SAlexander Motin 	pbp->bio_inbed++;
313*89b17223SAlexander Motin 	if (pbp->bio_children == pbp->bio_inbed) {
314*89b17223SAlexander Motin 		pbp->bio_completed = pbp->bio_length;
315*89b17223SAlexander Motin 		g_raid_iodone(pbp, bp->bio_error);
316*89b17223SAlexander Motin 	}
317*89b17223SAlexander Motin }
318*89b17223SAlexander Motin 
319*89b17223SAlexander Motin static int
320*89b17223SAlexander Motin g_raid_tr_free_raid0(struct g_raid_tr_object *tr)
321*89b17223SAlexander Motin {
322*89b17223SAlexander Motin 
323*89b17223SAlexander Motin 	return (0);
324*89b17223SAlexander Motin }
325*89b17223SAlexander Motin 
326*89b17223SAlexander Motin G_RAID_TR_DECLARE(g_raid_tr_raid0);
327