1 /* This file contains a driver for:
2 * /dev/klog - system log device
5 * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder)
6 * 7 July 2005 - Created (Ben Gras)
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
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 /*===========================================================================*
60 *===========================================================================*/
63 /* SEF local startup. */
66 /* Call the generic receive loop. */
67 chardriver_task(&log_dtab
, CHARDRIVER_ASYNC
);
72 /*===========================================================================*
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. */
94 /*===========================================================================*
96 *===========================================================================*/
97 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
99 /* Initialize the log driver. */
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;
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;
129 /*===========================================================================*
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 /*===========================================================================*
144 *===========================================================================*/
146 subwrite(struct logdevice
*log
, int count
, endpoint_t endpt
,
147 cp_grant_id_t grant
, size_t offset
, char *localbuf
)
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
);
161 if((r
=sys_safecopyfrom(endpt
, grant
, offset
,
162 (vir_bytes
)buf
, count
)) != OK
)
166 LOGINC(log
->log_write
, count
);
167 log
->log_size
+= count
;
169 if(log
->log_size
> LOG_SIZE
) {
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
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
);
192 printf("log`subwrite: send to %d failed: %d\n",
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
) {
210 m
.m_type
= DEV_SEL_REPL2
;
211 m
.DEV_SEL_OPS
= log
->log_select_ready_ops
;
214 printf("select sending DEV_SEL_REPL2\n");
216 r
= send(log
->log_select_proc
, &m
);
220 "log`subwrite: send to %d failed: %d\n",
221 log
->log_select_proc
, r
);
223 log
->log_selected
&= ~log
->log_select_ready_ops
;
230 /*===========================================================================*
232 *===========================================================================*/
234 log_append(char *buf
, int count
)
238 if(count
< 1) return;
239 if(count
> LOG_SIZE
) skip
= count
- LOG_SIZE
;
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,
250 /*===========================================================================*
252 *===========================================================================*/
254 subread(struct logdevice
*log
, int count
, endpoint_t endpt
,
255 cp_grant_id_t grant
, size_t offset
)
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
)
269 LOGINC(log
->log_read
, count
);
270 log
->log_size
-= count
;
275 /*===========================================================================*
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. */
291 int accumulated_read
= 0;
292 struct logdevice
*log
;
293 size_t vir_offset
= 0;
295 if(log_device
< 0 || log_device
>= NR_DEVS
)
298 /* Get minor device number and check for /dev/null. */
299 log
= &logdevices
[log_device
];
302 /* How much to transfer and where to / from. */
303 count
= iov
->iov_size
;
304 grant
= iov
->iov_addr
;
306 switch (log_device
) {
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.
317 if (!log
->log_size
) {
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
;
328 printf("blocked %d (%d)\n",
329 log
->log_source
, log
->log_proc_nr
);
333 count
= subread(log
, count
, endpt
, grant
, vir_offset
);
337 accumulated_read
+= count
;
339 count
= subwrite(log
, count
, endpt
, grant
, vir_offset
, NULL
);
344 /* Unknown (illegal) minor device. */
349 /* Book the number of bytes transferred. */
351 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
356 /*============================================================================*
358 *============================================================================*/
359 static int log_do_open(message
*m_ptr
)
361 if (log_prepare(m_ptr
->DEVICE
) == NULL
) return(ENXIO
);
365 /*============================================================================*
367 *============================================================================*/
368 static int log_cancel(message
*m_ptr
)
372 if(d
< 0 || d
>= NR_DEVS
)
374 logdevices
[d
].log_proc_nr
= NONE
;
375 logdevices
[d
].log_revive_alerted
= 0;
379 /*============================================================================*
381 *============================================================================*/
382 static int log_other(message
*m_ptr
)
386 /* This function gets messages that the generic driver doesn't
389 if (is_notify(m_ptr
->m_type
)) {
393 switch(m_ptr
->m_type
) {
395 printf("log_other: unexpected DEV_STATUS request\n");
406 /*============================================================================*
408 *============================================================================*/
409 static int log_select(message
*m_ptr
)
411 int d
, ready_ops
= 0, ops
= 0;
413 if(d
< 0 || d
>= NR_DEVS
) {
415 printf("line %d? EINVAL\n", d
);
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) {
425 printf("log can read; size %d\n", logdevices
[d
].log_size
);
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
;
441 printf("log setting selector.\n");
446 printf("log returning ops %d\n", ready_ops
);