1 /* daemon.c: kernel part of Vinum daemon */
3 * Copyright (c) 1997, 1998
4 * Nan Yang Computer Services Limited. All rights reserved.
6 * This software is distributed under the so-called ``Berkeley
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
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.
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 $
39 * $DragonFly: src/sys/dev/raid/vinum/vinumdaemon.c,v 1.12 2008/06/05 18:06:31 swildner Exp $
46 #include <sys/reboot.h>
50 void recover_io(struct request
*rq
);
52 int daemon_options
= 0; /* options */
53 int daemonpid
; /* PID of daemon */
54 struct daemonq
*daemonq
; /* daemon's work queue */
55 struct daemonq
*dqend
; /* and the end of the queue */
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.
64 struct daemonq intq
[INTQSIZE
]; /* queue elements for interrupt context */
65 struct daemonq
*intqp
; /* and pointer in it */
70 struct daemonq
*request
;
72 curproc
->p_flag
|= P_SYSTEM
; /* we're a system process */
73 daemon_save_config(); /* start by saving the configuration */
74 daemonpid
= curproc
->p_pid
; /* mark our territory */
76 tsleep(&vinum_daemon
, 0, "vinum", 0); /* wait for something to happen */
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.
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");
89 while (daemonq
!= NULL
) { /* we have work to do, */
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 */
97 switch (request
->type
) {
99 * We had an I/O error on a request. Go through the
100 * request and try to salvage it
102 case daemonrq_ioerror
:
103 if (daemon_options
& daemon_verbose
) {
104 struct request
*rq
= request
->info
.rq
;
107 "vinum: recovering I/O request: %p\n%s dev %d.%d, offset 0x%012llx, length %d\n",
109 (rq
->bio
->bio_buf
->b_cmd
== BUF_CMD_READ
) ? "Read" : "Write",
110 major((cdev_t
)rq
->bio
->bio_driver_info
),
111 minor((cdev_t
)rq
->bio
->bio_driver_info
),
112 (long long)rq
->bio
->bio_offset
,
113 rq
->bio
->bio_buf
->b_bcount
);
115 recover_io(request
->info
.rq
); /* the failed request */
119 * Write the config to disk. We could end up with
120 * quite a few of these in a row. Only honour the
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 */
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
136 if (daemon_options
& daemon_verbose
)
137 log(LOG_INFO
, "vinum: saving config\n");
138 daemon_save_config(); /* save it */
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 */
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 */
153 wakeup(&vinumclose
); /* and wake any waiting vinum(8)s */
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 */
162 case daemonrq_closedrive
: /* close a drive */
163 close_drive(request
->info
.drive
); /* do it */
166 case daemonrq_init
: /* initialize a plex */
168 case daemonrq_revive
: /* revive a subdisk */
172 log(LOG_WARNING
, "Invalid request\n");
175 if (request
->privateinuse
) /* one of ours, */
176 request
->privateinuse
= 0; /* no longer in use */
178 Free(request
); /* return it */
184 * Recover a failed I/O operation.
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.
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
199 recover_io(struct request
*rq
)
204 * vinumstrategy(rq->bio);
206 * Negotiate with phk to get it fixed.
207 * Reissue the command.
209 dev_dstrategy((cdev_t
)rq
->bio
->bio_driver_info
, rq
->bio
);
212 /* Functions called to interface with the daemon */
214 /* queue a request for the daemon */
216 queue_daemon_request(enum daemonrq type
, union daemoninfo info
)
218 struct daemonq
*qelt
= (struct daemonq
*) Malloc(sizeof(struct daemonq
));
220 if (qelt
== NULL
) { /* malloc failed, we're prepared for that */
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.
226 if (intqp
->privateinuse
) /* still in use? */
227 return; /* yes, give up */
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 */
233 qelt
->privateinuse
= 0;
235 qelt
->next
= NULL
; /* end of the chain */
239 if (daemonq
) { /* something queued already */
242 } else { /* queue is empty, */
243 daemonq
= qelt
; /* this is the whole queue */
247 wakeup(&vinum_daemon
); /* and give the dæmon a kick */
251 * see if the daemon is running. Return 0 (no error)
252 * if it is, ESRCH otherwise
255 vinum_finddaemon(void)
259 if (daemonpid
!= 0) { /* we think we have a daemon, */
260 queue_daemon_request(daemonrq_ping
, (union daemoninfo
) 0); /* queue a ping */
261 result
= tsleep(&vinum_finddaemon
, 0, "reap", 2 * hz
);
262 if (result
== 0) /* yup, the daemon's up and running */
265 /* no daemon, or we couldn't talk to it: start it */
266 vinum_daemon(); /* start the daemon */
271 vinum_setdaemonopts(int options
)
273 daemon_options
= options
;