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: releng/5.0/sys/dev/vinum/vinumdaemon.c 106583 2002-11-07 21:52:51Z jhb $
39 */
40
41 #include <dev/vinum/vinumhdr.h>
42 #include <dev/vinum/request.h>
43
44 #ifdef VINUMDEBUG
45 #include <sys/reboot.h>
46 #endif
47
48 /* declarations */
49 void recover_io(struct request *rq);
50
51 int daemon_options = 0; /* options */
52 int daemonpid; /* PID of daemon */
53 struct daemonq *daemonq; /* daemon's work queue */
54 struct daemonq *dqend; /* and the end of the queue */
55
56 /*
57 * We normally call Malloc to get a queue element. In interrupt
58 * context, we can't guarantee that we'll get one, since we're not
59 * allowed to wait. If malloc fails, use one of these elements.
60 */
61
62 #define INTQSIZE 4
63 struct daemonq intq[INTQSIZE]; /* queue elements for interrupt context */
64 struct daemonq *intqp; /* and pointer in it */
65
66 void
67 vinum_daemon(void)
68 {
69 int s;
70 struct daemonq *request;
71
72 PROC_LOCK(curproc);
73 curproc->p_flag |= P_SYSTEM; /* we're a system process */
74 PROC_UNLOCK(curproc);
75 mtx_lock_spin(&sched_lock);
76 curproc->p_sflag |= PS_INMEM;
77 mtx_unlock_spin(&sched_lock);
78 daemon_save_config(); /* start by saving the configuration */
79 daemonpid = curproc->p_pid; /* mark our territory */
80 while (1) {
81 tsleep(&vinum_daemon, PRIBIO, "vinum", 0); /* wait for something to happen */
82
83 /*
84 * It's conceivable that, as the result of an
85 * I/O error, we'll be out of action long
86 * enough that another daemon gets started.
87 * That's OK, just give up gracefully.
88 */
89 if (curproc->p_pid != daemonpid) { /* we've been ousted in our sleep */
90 if (daemon_options & daemon_verbose)
91 log(LOG_INFO, "vinum: abdicating\n");
92 return;
93 }
94 while (daemonq != NULL) { /* we have work to do, */
95 s = splhigh(); /* don't get interrupted here */
96 request = daemonq; /* get the request */
97 daemonq = daemonq->next; /* and detach it */
98 if (daemonq == NULL) /* got to the end, */
99 dqend = NULL; /* no end any more */
100 splx(s);
101
102 switch (request->type) {
103 /*
104 * We had an I/O error on a request. Go through the
105 * request and try to salvage it
106 */
107 case daemonrq_ioerror:
108 if (daemon_options & daemon_verbose) {
109 struct request *rq = request->info.rq;
110
111 log(LOG_WARNING,
112 "vinum: recovering I/O request: %p\n%s dev %d.%d, offset 0x%llx, length %ld\n",
113 rq,
114 rq->bp->b_iocmd == BIO_READ ? "Read" : "Write",
115 major(rq->bp->b_dev),
116 minor(rq->bp->b_dev),
117 (long long)rq->bp->b_blkno,
118 rq->bp->b_bcount);
119 }
120 recover_io(request->info.rq); /* the failed request */
121 break;
122
123 /*
124 * Write the config to disk. We could end up with
125 * quite a few of these in a row. Only honour the
126 * last one
127 */
128 case daemonrq_saveconfig:
129 if ((daemonq == NULL) /* no more requests */
130 ||(daemonq->type != daemonrq_saveconfig)) { /* or the next isn't the same */
131 if (((daemon_options & daemon_noupdate) == 0) /* we're allowed to do it */
132 &&((vinum_conf.flags & VF_READING_CONFIG) == 0)) { /* and we're not building the config now */
133 /*
134 * We obviously don't want to save a
135 * partial configuration. Less obviously,
136 * we don't need to do anything if we're
137 * asked to write the config when we're
138 * building it up, because we save it at
139 * the end.
140 */
141 if (daemon_options & daemon_verbose)
142 log(LOG_INFO, "vinum: saving config\n");
143 daemon_save_config(); /* save it */
144 }
145 }
146 break;
147
148 case daemonrq_return: /* been told to stop */
149 if (daemon_options & daemon_verbose)
150 log(LOG_INFO, "vinum: stopping\n");
151 daemon_options |= daemon_stopped; /* note that we've stopped */
152 Free(request);
153 while (daemonq != NULL) { /* backed up requests, */
154 request = daemonq; /* get the request */
155 daemonq = daemonq->next; /* and detach it */
156 Free(request); /* then free it */
157 }
158 wakeup(&vinumclose); /* and wake any waiting vinum(8)s */
159 return;
160
161 case daemonrq_ping: /* tell the caller we're here */
162 if (daemon_options & daemon_verbose)
163 log(LOG_INFO, "vinum: ping reply\n");
164 wakeup(&vinum_finddaemon); /* wake up the caller */
165 break;
166
167 case daemonrq_closedrive: /* close a drive */
168 close_drive(request->info.drive); /* do it */
169 break;
170
171 case daemonrq_init: /* initialize a plex */
172 /* XXX */
173 case daemonrq_revive: /* revive a subdisk */
174 /* XXX */
175 /* FALLTHROUGH */
176 default:
177 log(LOG_WARNING, "Invalid request\n");
178 break;
179 }
180 if (request->privateinuse) /* one of ours, */
181 request->privateinuse = 0; /* no longer in use */
182 else
183 Free(request); /* return it */
184 }
185 }
186 }
187
188 /*
189 * Recover a failed I/O operation.
190 *
191 * The correct way to do this is to examine the request and determine
192 * how to recover each individual failure. In the case of a write,
193 * this could be as simple as doing nothing: the defective drives may
194 * already be down, and there may be nothing else to do. In case of
195 * a read, it will be necessary to retry if there are alternative
196 * copies of the data.
197 *
198 * The easy way (here) is just to reissue the request. This will take
199 * a little longer, but nothing like as long as the failure will have
200 * taken.
201 *
202 */
203 void
204 recover_io(struct request *rq)
205 {
206 /*
207 * This should read:
208 *
209 * vinumstrategy(rq->bp);
210 *
211 * Negotiate with phk to get it fixed.
212 */
213 DEV_STRATEGY(rq->bp, 0); /* reissue the command */
214 }
215
216 /* Functions called to interface with the daemon */
217
218 /* queue a request for the daemon */
219 void
220 queue_daemon_request(enum daemonrq type, union daemoninfo info)
221 {
222 int s;
223
224 struct daemonq *qelt = (struct daemonq *) Malloc(sizeof(struct daemonq));
225
226 if (qelt == NULL) { /* malloc failed, we're prepared for that */
227 /*
228 * Take one of our spares. Give up if it's still in use; the only
229 * message we're likely to get here is a 'drive failed' message,
230 * and that'll come by again if we miss it.
231 */
232 if (intqp->privateinuse) /* still in use? */
233 return; /* yes, give up */
234 qelt = intqp++;
235 if (intqp == &intq[INTQSIZE]) /* got to the end, */
236 intqp = intq; /* wrap around */
237 qelt->privateinuse = 1; /* it's ours, and it's in use */
238 } else
239 qelt->privateinuse = 0;
240
241 qelt->next = NULL; /* end of the chain */
242 qelt->type = type;
243 qelt->info = info;
244 s = splhigh();
245 if (daemonq) { /* something queued already */
246 dqend->next = qelt;
247 dqend = qelt;
248 } else { /* queue is empty, */
249 daemonq = qelt; /* this is the whole queue */
250 dqend = qelt;
251 }
252 splx(s);
253 wakeup(&vinum_daemon); /* and give the dæmon a kick */
254 }
255
256 /*
257 * see if the daemon is running. Return 0 (no error)
258 * if it is, ESRCH otherwise
259 */
260 int
261 vinum_finddaemon()
262 {
263 int result;
264
265 if (daemonpid != 0) { /* we think we have a daemon, */
266 queue_daemon_request(daemonrq_ping, (union daemoninfo) 0); /* queue a ping */
267 result = tsleep(&vinum_finddaemon, PUSER, "reap", 2 * hz);
268 if (result == 0) /* yup, the daemon's up and running */
269 return 0;
270 }
271 /* no daemon, or we couldn't talk to it: start it */
272 vinum_daemon(); /* start the daemon */
273 return 0;
274 }
275
276 int
277 vinum_setdaemonopts(int options)
278 {
279 daemon_options = options;
280 return 0;
281 }
Cache object: 68ac6e6250ba73c0c1f64ee35b7119b2
|