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