mkfs, mkproto: minor improvements
[minix.git] / drivers / log / log.c
blob44f2d55cf5fcca2c2d3950f35574fd0ad33015a5
1 /* This file contains a driver for:
2 * /dev/klog - system log device
4 * Changes:
5 * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder)
6 * 7 July 2005 - Created (Ben Gras)
7 */
9 #include "log.h"
10 #include <sys/time.h>
11 #include <sys/select.h>
12 #include <minix/endpoint.h>
14 #define LOG_DEBUG 0 /* enable/ disable debugging */
16 #define NR_DEVS 1 /* number of minor devices */
17 #define MINOR_KLOG 0 /* /dev/klog */
19 #define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0)
21 struct logdevice logdevices[NR_DEVS];
22 static struct device log_geom[NR_DEVS]; /* base and size of devices */
23 static int log_device = -1; /* current device */
25 static struct device *log_prepare(dev_t device);
26 static int log_transfer(endpoint_t endpt, int opcode, u64_t position,
27 iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
28 flags);
29 static int log_do_open(message *m_ptr);
30 static int log_cancel(message *m_ptr);
31 static int log_select(message *m_ptr);
32 static int log_other(message *m_ptr);
33 static int subread(struct logdevice *log, int count, endpoint_t endpt,
34 cp_grant_id_t grant, size_t);
36 /* Entry points to this driver. */
37 static struct chardriver log_dtab = {
38 log_do_open, /* open or mount */
39 do_nop, /* nothing on a close */
40 nop_ioctl, /* ioctl nop */
41 log_prepare, /* prepare for I/O on a given minor device */
42 log_transfer, /* do the I/O */
43 nop_cleanup, /* no need to clean up */
44 nop_alarm, /* no alarm */
45 log_cancel, /* CANCEL request */
46 log_select, /* DEV_SELECT request */
47 log_other /* Unrecognized messages */
50 /* SEF functions and variables. */
51 static void sef_local_startup(void);
52 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
53 EXTERN int sef_cb_lu_prepare(int state);
54 EXTERN int sef_cb_lu_state_isvalid(int state);
55 EXTERN void sef_cb_lu_state_dump(int state);
56 static void sef_cb_signal_handler(int signo);
58 /*===========================================================================*
59 * main *
60 *===========================================================================*/
61 int main(void)
63 /* SEF local startup. */
64 sef_local_startup();
66 /* Call the generic receive loop. */
67 chardriver_task(&log_dtab, CHARDRIVER_ASYNC);
69 return(OK);
72 /*===========================================================================*
73 * sef_local_startup *
74 *===========================================================================*/
75 static void sef_local_startup()
77 /* Register init callbacks. */
78 sef_setcb_init_fresh(sef_cb_init_fresh);
79 sef_setcb_init_lu(sef_cb_init_fresh);
80 sef_setcb_init_restart(sef_cb_init_fresh);
82 /* Register live update callbacks. */
83 sef_setcb_lu_prepare(sef_cb_lu_prepare);
84 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
85 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
87 /* Register signal callbacks. */
88 sef_setcb_signal_handler(sef_cb_signal_handler);
90 /* Let SEF perform startup. */
91 sef_startup();
94 /*===========================================================================*
95 * sef_cb_init_fresh *
96 *===========================================================================*/
97 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
99 /* Initialize the log driver. */
100 int i;
102 /* Initialize log devices. */
103 for(i = 0; i < NR_DEVS; i++) {
104 log_geom[i].dv_size = cvul64(LOG_SIZE);
105 log_geom[i].dv_base = cvul64((long)logdevices[i].log_buffer);
106 logdevices[i].log_size = logdevices[i].log_read =
107 logdevices[i].log_write =
108 logdevices[i].log_select_alerted =
109 logdevices[i].log_selected =
110 logdevices[i].log_select_ready_ops = 0;
111 logdevices[i].log_source = NONE;
112 logdevices[i].log_revive_alerted = 0;
115 return(OK);
118 /*===========================================================================*
119 * sef_cb_signal_handler *
120 *===========================================================================*/
121 static void sef_cb_signal_handler(int signo)
123 /* Only check for a pending message from the kernel, ignore anything else. */
124 if (signo != SIGKMESS) return;
126 do_new_kmess();
129 /*===========================================================================*
130 * log_prepare *
131 *===========================================================================*/
132 static struct device *log_prepare(dev_t device)
134 /* Prepare for I/O on a device: check if the minor device number is ok. */
136 if (device >= NR_DEVS) return(NULL);
137 log_device = (int) device;
139 return(&log_geom[device]);
142 /*===========================================================================*
143 * subwrite *
144 *===========================================================================*/
145 static int
146 subwrite(struct logdevice *log, int count, endpoint_t endpt,
147 cp_grant_id_t grant, size_t offset, char *localbuf)
149 int d, r;
150 char *buf;
151 message m;
153 if (log->log_write + count > LOG_SIZE)
154 count = LOG_SIZE - log->log_write;
155 buf = log->log_buffer + log->log_write;
157 if(localbuf != NULL) {
158 memcpy(buf, localbuf, count);
160 else {
161 if((r=sys_safecopyfrom(endpt, grant, offset,
162 (vir_bytes)buf, count)) != OK)
163 return r;
166 LOGINC(log->log_write, count);
167 log->log_size += count;
169 if(log->log_size > LOG_SIZE) {
170 int overflow;
171 overflow = log->log_size - LOG_SIZE;
172 log->log_size -= overflow;
173 LOGINC(log->log_read, overflow);
176 if(log->log_size > 0 && log->log_source != NONE &&
177 !log->log_revive_alerted) {
178 /* Someone who was suspended on read can now
179 * be revived.
181 log->log_status = subread(log, log->log_iosize,
182 log->log_source, log->log_user_grant,
183 log->log_user_offset);
185 m.m_type = DEV_REVIVE;
186 m.REP_ENDPT = log->log_proc_nr;
187 m.REP_STATUS = log->log_status;
188 m.REP_IO_GRANT = log->log_user_grant;
189 r= send(log->log_source, &m);
190 if (r != OK)
192 printf("log`subwrite: send to %d failed: %d\n",
193 log->log_source, r);
195 log->log_source = NONE;
198 if(log->log_size > 0)
199 log->log_select_ready_ops |= SEL_RD;
201 if(log->log_size > 0 && log->log_selected &&
202 !(log->log_select_alerted)) {
203 /* Someone(s) who was/were select()ing can now
204 * be awoken. If there was a blocking read (above),
205 * this can only happen if the blocking read didn't
206 * swallow all the data (log_size > 0).
208 if(log->log_selected & SEL_RD) {
209 d= log-logdevices;
210 m.m_type = DEV_SEL_REPL2;
211 m.DEV_SEL_OPS = log->log_select_ready_ops;
212 m.DEV_MINOR = d;
213 #if LOG_DEBUG
214 printf("select sending DEV_SEL_REPL2\n");
215 #endif
216 r= send(log->log_select_proc, &m);
217 if (r != OK)
219 printf(
220 "log`subwrite: send to %d failed: %d\n",
221 log->log_select_proc, r);
223 log->log_selected &= ~log->log_select_ready_ops;
227 return count;
230 /*===========================================================================*
231 * log_append *
232 *===========================================================================*/
233 void
234 log_append(char *buf, int count)
236 int w = 0, skip = 0;
238 if(count < 1) return;
239 if(count > LOG_SIZE) skip = count - LOG_SIZE;
240 count -= skip;
241 buf += skip;
242 w = subwrite(&logdevices[0], count, SELF, GRANT_INVALID, 0, buf);
244 if(w > 0 && w < count)
245 subwrite(&logdevices[0], count-w, SELF, GRANT_INVALID, 0,
246 buf + w);
247 return;
250 /*===========================================================================*
251 * subread *
252 *===========================================================================*/
253 static int
254 subread(struct logdevice *log, int count, endpoint_t endpt,
255 cp_grant_id_t grant, size_t offset)
257 char *buf;
258 int r;
259 if (count > log->log_size)
260 count = log->log_size;
261 if (log->log_read + count > LOG_SIZE)
262 count = LOG_SIZE - log->log_read;
264 buf = log->log_buffer + log->log_read;
265 if((r=sys_safecopyto(endpt, grant, offset,
266 (vir_bytes)buf, count)) != OK)
267 return r;
269 LOGINC(log->log_read, count);
270 log->log_size -= count;
272 return count;
275 /*===========================================================================*
276 * log_transfer *
277 *===========================================================================*/
278 static int log_transfer(
279 endpoint_t endpt, /* endpoint of grant owner */
280 int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */
281 u64_t UNUSED(position), /* offset on device to read or write */
282 iovec_t *iov, /* pointer to read or write request vector */
283 unsigned int nr_req, /* length of request vector */
284 endpoint_t user_endpt, /* endpoint of user process */
285 unsigned int UNUSED(flags)
288 /* Read or write one the driver's minor devices. */
289 int count;
290 cp_grant_id_t grant;
291 int accumulated_read = 0;
292 struct logdevice *log;
293 size_t vir_offset = 0;
295 if(log_device < 0 || log_device >= NR_DEVS)
296 return EIO;
298 /* Get minor device number and check for /dev/null. */
299 log = &logdevices[log_device];
301 while (nr_req > 0) {
302 /* How much to transfer and where to / from. */
303 count = iov->iov_size;
304 grant = iov->iov_addr;
306 switch (log_device) {
308 case MINOR_KLOG:
309 if (opcode == DEV_GATHER_S) {
310 if (log->log_source != NONE || count < 1) {
311 /* There's already someone hanging to read, or
312 * no real I/O requested.
314 return(OK);
317 if (!log->log_size) {
318 if(accumulated_read)
319 return OK;
320 /* No data available; let caller block. */
321 log->log_source = endpt;
322 log->log_iosize = count;
323 log->log_user_grant = grant;
324 log->log_user_offset = 0;
325 log->log_revive_alerted = 0;
326 log->log_proc_nr = user_endpt;
327 #if LOG_DEBUG
328 printf("blocked %d (%d)\n",
329 log->log_source, log->log_proc_nr);
330 #endif
331 return(EDONTREPLY);
333 count = subread(log, count, endpt, grant, vir_offset);
334 if(count < 0) {
335 return count;
337 accumulated_read += count;
338 } else {
339 count = subwrite(log, count, endpt, grant, vir_offset, NULL);
340 if(count < 0)
341 return count;
343 break;
344 /* Unknown (illegal) minor device. */
345 default:
346 return(EINVAL);
349 /* Book the number of bytes transferred. */
350 vir_offset += count;
351 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
353 return(OK);
356 /*============================================================================*
357 * log_do_open *
358 *============================================================================*/
359 static int log_do_open(message *m_ptr)
361 if (log_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
362 return(OK);
365 /*============================================================================*
366 * log_cancel *
367 *============================================================================*/
368 static int log_cancel(message *m_ptr)
370 int d;
371 d = m_ptr->TTY_LINE;
372 if(d < 0 || d >= NR_DEVS)
373 return EINVAL;
374 logdevices[d].log_proc_nr = NONE;
375 logdevices[d].log_revive_alerted = 0;
376 return(OK);
379 /*============================================================================*
380 * log_other *
381 *============================================================================*/
382 static int log_other(message *m_ptr)
384 int r;
386 /* This function gets messages that the generic driver doesn't
387 * understand.
389 if (is_notify(m_ptr->m_type)) {
390 return EINVAL;
393 switch(m_ptr->m_type) {
394 case DEV_STATUS: {
395 printf("log_other: unexpected DEV_STATUS request\n");
396 r = EDONTREPLY;
397 break;
399 default:
400 r = EINVAL;
401 break;
403 return r;
406 /*============================================================================*
407 * log_select *
408 *============================================================================*/
409 static int log_select(message *m_ptr)
411 int d, ready_ops = 0, ops = 0;
412 d = m_ptr->TTY_LINE;
413 if(d < 0 || d >= NR_DEVS) {
414 #if LOG_DEBUG
415 printf("line %d? EINVAL\n", d);
416 #endif
417 return EINVAL;
420 ops = m_ptr->USER_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
422 /* Read blocks when there is no log. */
423 if((m_ptr->USER_ENDPT & SEL_RD) && logdevices[d].log_size > 0) {
424 #if LOG_DEBUG
425 printf("log can read; size %d\n", logdevices[d].log_size);
426 #endif
427 ready_ops |= SEL_RD; /* writes never block */
430 /* Write never blocks. */
431 if(m_ptr->USER_ENDPT & SEL_WR) ready_ops |= SEL_WR;
433 /* Enable select calback if no operations were
434 * ready to go, but operations were requested,
435 * and notify was enabled.
437 if((m_ptr->USER_ENDPT & SEL_NOTIFY) && ops && !ready_ops) {
438 logdevices[d].log_selected |= ops;
439 logdevices[d].log_select_proc = m_ptr->m_source;
440 #if LOG_DEBUG
441 printf("log setting selector.\n");
442 #endif
445 #if LOG_DEBUG
446 printf("log returning ops %d\n", ready_ops);
447 #endif
449 return(ready_ops);