]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/vinum/vinumdaemon.c
Refinement on previous fix for mutex destruction: make sure we don't
[FreeBSD/FreeBSD.git] / sys / dev / vinum / vinumdaemon.c
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$
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                         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 }