kernel - Major signal path adjustments to fix races, tsleep race fixes, +more
[dragonfly.git] / sys / dev / raid / vinum / vinumdaemon.c
Content-type: text/html gitweb.dragonflybsd.org Git - dragonfly.git/blame - sys/dev/raid/vinum/vinumdaemon.c


500 - Internal Server Error

Malformed UTF-8 character (fatal) at /usr/local/www/cgi-bin/gitweb.cgi line 1535, <$fd> line 615.
CommitLineData
984263bc
MD
1/* daemon.c: kernel part of Vinum daemon */
2/*-
3 * Copyright (c) 1997, 1998
4 * Nan Yang Computer Services Limited. All rights reserved.
5 *
6 * This software is distributed under the so-called ``Berkeley
7 * License'':
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Nan Yang Computer
20 * Services Limited.
21 * 4. Neither the name of the Company nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * This software is provided ``as is'', and any express or implied
26 * warranties, including, but not limited to, the implied warranties of
27 * merchantability and fitness for a particular purpose are disclaimed.
28 * In no event shall the company or contributors be liable for any
29 * direct, indirect, incidental, special, exemplary, or consequential
30 * damages (including, but not limited to, procurement of substitute
31 * goods or services; loss of use, data, or profits; or business
32 * interruption) however caused and on any theory of liability, whether
33 * in contract, strict liability, or tort (including negligence or
34 * otherwise) arising in any way out of the use of this software, even if
35 * advised of the possibility of such damage.
36 *
37 * $Id: vinumdaemon.c,v 1.8 2000/01/03 05:22:03 grog Exp grog $
38 * $FreeBSD: src/sys/dev/vinum/vinumdaemon.c,v 1.16 2000/01/05 06:03:56 grog Exp $
3641b7ca 39 * $DragonFly: src/sys/dev/raid/vinum/vinumdaemon.c,v 1.12 2008/06/05 18:06:31 swildner Exp $
984263bc
MD
40 */
41
1f2de5d4
MD
42#include "vinumhdr.h"
43#include "request.h"
984263bc
MD
44
45#ifdef VINUMDEBUG
46#include <sys/reboot.h>
47#endif
48
49/* declarations */
50void recover_io(struct request *rq);
51
52int daemon_options = 0; /* options */
53int daemonpid; /* PID of daemon */
54struct daemonq *daemonq; /* daemon's work queue */
55struct daemonq *dqend; /* and the end of the queue */
56
57/*
58 * We normally call Malloc to get a queue element. In interrupt
59 * context, we can't guarantee that we'll get one, since we're not
60 * allowed to wait. If malloc fails, use one of these elements.
61 */
62
63#define INTQSIZE 4
64struct daemonq intq[INTQSIZE]; /* queue elements for interrupt context */
65struct daemonq *intqp; /* and pointer in it */
66
67void
68vinum_daemon(void)
69{
984263bc
MD
70 struct daemonq *request;
71
4643740a 72 curproc->p_flags |= P_SYSTEM; /* we're a system process */
984263bc
MD
73 daemon_save_config(); /* start by saving the configuration */
74 daemonpid = curproc->p_pid; /* mark our territory */
75 while (1) {
377d4740 76 tsleep(&vinum_daemon, 0, "vinum", 0); /* wait for something to happen */
984263bc
MD
77
78 /*
79 * It's conceivable that, as the result of an
80 * I/O error, we'll be out of action long
81 * enough that another daemon gets started.
82 * That's OK, just give up gracefully.
83 */
84 if (curproc->p_pid != daemonpid) { /* we've been ousted in our sleep */
85 if (daemon_options & daemon_verbose)
86 log(LOG_INFO, "vinum: abdicating\n");
87 return;
88 }
89 while (daemonq != NULL) { /* we have work to do, */
407c6ab2 90 crit_enter();
984263bc
MD
91 request = daemonq; /* get the request */
92 daemonq = daemonq->next; /* and detach it */
93 if (daemonq == NULL) /* got to the end, */
94 dqend = NULL; /* no end any more */
407c6ab2 95 crit_exit();
984263bc
MD
96
97 switch (request->type) {
98 /*
99 * We had an I/O error on a request. Go through the
100 * request and try to salvage it
101 */
102 case daemonrq_ioerror:
103 if (daemon_options & daemon_verbose) {
104 struct request *rq = request->info.rq;
105
106 log(LOG_WARNING,
54078292 107 "vinum: recovering I/O request: %p\n%s dev %d.%d, offset 0x%012llx, length %d\n",
984263bc 108 rq,
10f3fee5 109 (rq->bio->bio_buf->b_cmd == BUF_CMD_READ) ? "Read" : "Write",
b13267a5
MD
110 major((cdev_t)rq->bio->bio_driver_info),
111 minor((cdev_t)rq->bio->bio_driver_info),
5bcacc1c 112 (long long)rq->bio->bio_offset,
81b5c339 113 rq->bio->bio_buf->b_bcount);
984263bc
MD
114 }
115 recover_io(request->info.rq); /* the failed request */
116 break;
117
118 /*
119 * Write the config to disk. We could end up with
120 * quite a few of these in a row. Only honour the
121 * last one
122 */
123 case daemonrq_saveconfig:
124 if ((daemonq == NULL) /* no more requests */
125 ||(daemonq->type != daemonrq_saveconfig)) { /* or the next isn't the same */
126 if (((daemon_options & daemon_noupdate) == 0) /* we're allowed to do it */
127 &&((vinum_conf.flags & VF_READING_CONFIG) == 0)) { /* and we're not building the config now */
128 /*
129 * We obviously don't want to save a
130 * partial configuration. Less obviously,
131 * we don't need to do anything if we're
132 * asked to write the config when we're
133 * building it up, because we save it at
134 * the end.
135 */
136 if (daemon_options & daemon_verbose)
137 log(LOG_INFO, "vinum: saving config\n");
138 daemon_save_config(); /* save it */
139 }
140 }
141 break;
142
143 case daemonrq_return: /* been told to stop */
144 if (daemon_options & daemon_verbose)
145 log(LOG_INFO, "vinum: stopping\n");
146 daemon_options |= daemon_stopped; /* note that we've stopped */
147 Free(request);
148 while (daemonq != NULL) { /* backed up requests, */
149 request = daemonq; /* get the request */
150 daemonq = daemonq->next; /* and detach it */
151 Free(request); /* then free it */
152 }
153 wakeup(&vinumclose); /* and wake any waiting vinum(8)s */
154 return;
155
156 case daemonrq_ping: /* tell the caller we're here */
157 if (daemon_options & daemon_verbose)
158 log(LOG_INFO, "vinum: ping reply\n");
159 wakeup(&vinum_finddaemon); /* wake up the caller */
160 break;
161
162 case daemonrq_closedrive: /* close a drive */
163 close_drive(request->info.drive); /* do it */
164 break;
165
166 case daemonrq_init: /* initialize a plex */
167 /* XXX */
168 case daemonrq_revive: /* revive a subdisk */
169 /* XXX */
170 /* FALLTHROUGH */
171 default:
172 log(LOG_WARNING, "Invalid request\n");
173 break;
174 }
175 if (request->privateinuse) /* one of ours, */
176 request->privateinuse = 0; /* no longer in use */
177 else
178 Free(request); /* return it */
179 }
180 }
181}
182
183/*
184 * Recover a failed I/O operation.
185 *
186 * The correct way to do this is to examine the request and determine
187 * how to recover each individual failure. In the case of a write,
188 * this could be as simple as doing nothing: the defective drives may
189 * already be down, and there may be nothing else to do. In case of
190 * a read, it will be necessary to retry if there are alternative
191 * copies of the data.
192 *
193 * The easy way (here) is just to reissue the request. This will take
194 * a little longer, but nothing like as long as the failure will have
195 * taken.
196 *
197 */
198void
199recover_io(struct request *rq)
200{
201 /*
202 * This should read:
203 *
81b5c339 204 * vinumstrategy(rq->bio);
984263bc
MD
205 *
206 * Negotiate with phk to get it fixed.
81b5c339 207 * Reissue the command.
984263bc 208 */
b13267a5 209 dev_dstrategy((cdev_t)rq->bio->bio_driver_info, rq->bio);
984263bc
MD
210}
211
212/* Functions called to interface with the daemon */
213
214/* queue a request for the daemon */
215void
216queue_daemon_request(enum daemonrq type, union daemoninfo info)
217{
984263bc
MD
218 struct daemonq *qelt = (struct daemonq *) Malloc(sizeof(struct daemonq));
219
220 if (qelt == NULL) { /* malloc failed, we're prepared for that */
221 /*
222 * Take one of our spares. Give up if it's still in use; the only
223 * message we're likely to get here is a 'drive failed' message,
224 * and that'll come by again if we miss it.
225 */
226 if (intqp->privateinuse) /* still in use? */
227 return; /* yes, give up */
228 qelt = intqp++;
229 if (intqp == &intq[INTQSIZE]) /* got to the end, */
230 intqp = intq; /* wrap around */
231 qelt->privateinuse = 1; /* it's ours, and it's in use */
232 } else
233 qelt->privateinuse = 0;
234
235 qelt->next = NULL; /* end of the chain */
236 qelt->type = type;
237 qelt->info = info;
407c6ab2 238 crit_enter();
984263bc
MD
239 if (daemonq) { /* something queued already */
240 dqend->next = qelt;
241 dqend = qelt;
242 } else { /* queue is empty, */
243 daemonq = qelt; /* this is the whole queue */
244 dqend = qelt;
245 }
407c6ab2 246 crit_exit();
984263bc
MD
247