source: branches/minix3-book/drivers/log/log.c@ 20

Last change on this file since 20 was 4, checked in by Mattia Monga, 14 years ago

Importazione sorgenti libro

File size: 13.5 KB
RevLine 
[4]1/* This file contains a driver for:
2 * /dev/klog - system log device
3 *
4 * Changes:
5 * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder)
6 * 7 July 2005 - Created (Ben Gras)
7 */
8
9#include "log.h"
10#include <sys/time.h>
11#include <sys/select.h>
12#include "../../kernel/const.h"
13#include "../../kernel/type.h"
14
15#define LOG_DEBUG 0 /* enable/ disable debugging */
16
17#define NR_DEVS 1 /* number of minor devices */
18#define MINOR_KLOG 0 /* /dev/klog */
19
20#define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0)
21
22PUBLIC struct logdevice logdevices[NR_DEVS];
23PRIVATE struct device log_geom[NR_DEVS]; /* base and size of devices */
24PRIVATE int log_device = -1; /* current device */
25
26FORWARD _PROTOTYPE( char *log_name, (void) );
27FORWARD _PROTOTYPE( struct device *log_prepare, (int device) );
28FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, off_t position,
29 iovec_t *iov, unsigned nr_req) );
30FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) );
31FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) );
32FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) );
33FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, message *m_ptr) );
34FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr) );
35FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) );
36FORWARD _PROTOTYPE( int subread, (struct logdevice *log, int count, int proc_nr, vir_bytes user_vir) );
37
38/* Entry points to this driver. */
39PRIVATE struct driver log_dtab = {
40 log_name, /* current device's name */
41 log_do_open, /* open or mount */
42 do_nop, /* nothing on a close */
43 do_nop, /* ioctl nop */
44 log_prepare, /* prepare for I/O on a given minor device */
45 log_transfer, /* do the I/O */
46 nop_cleanup, /* no need to clean up */
47 log_geometry, /* geometry */
48 log_signal, /* handle system signal */
49 nop_alarm, /* no alarm */
50 log_cancel, /* CANCEL request */
51 log_select, /* DEV_SELECT request */
52 log_other, /* Unrecognized messages */
53 NULL /* HW int */
54};
55
56extern int device_caller;
57
58/*===========================================================================*
59 * main *
60 *===========================================================================*/
61PUBLIC int main(void)
62{
63 int i;
64 for(i = 0; i < NR_DEVS; i++) {
65 log_geom[i].dv_size = cvul64(LOG_SIZE);
66 log_geom[i].dv_base = cvul64((long)logdevices[i].log_buffer);
67 logdevices[i].log_size = logdevices[i].log_read =
68 logdevices[i].log_write =
69 logdevices[i].log_select_alerted =
70 logdevices[i].log_selected =
71 logdevices[i].log_select_ready_ops = 0;
72 logdevices[i].log_proc_nr = 0;
73 logdevices[i].log_revive_alerted = 0;
74 }
75 driver_task(&log_dtab);
76 return(OK);
77}
78
79/*===========================================================================*
80 * log_name *
81 *===========================================================================*/
82PRIVATE char *log_name()
83{
84/* Return a name for the current device. */
85 static char name[] = "log";
86 return name;
87}
88
89/*===========================================================================*
90 * log_prepare *
91 *===========================================================================*/
92PRIVATE struct device *log_prepare(device)
93int device;
94{
95/* Prepare for I/O on a device: check if the minor device number is ok. */
96
97 if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
98 log_device = device;
99
100 return(&log_geom[device]);
101}
102
103/*===========================================================================*
104 * subwrite *
105 *===========================================================================*/
106PRIVATE int
107subwrite(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir)
108{
109 char *buf;
110 int r;
111 if (log->log_write + count > LOG_SIZE)
112 count = LOG_SIZE - log->log_write;
113 buf = log->log_buffer + log->log_write;
114
115 if(proc_nr == SELF) {
116 memcpy(buf, (char *) user_vir, count);
117 }
118 else {
119 if((r=sys_vircopy(proc_nr,D,user_vir, SELF,D,(int)buf, count)) != OK)
120 return r;
121 }
122
123 LOGINC(log->log_write, count);
124 log->log_size += count;
125
126 if(log->log_size > LOG_SIZE) {
127 int overflow;
128 overflow = log->log_size - LOG_SIZE;
129 log->log_size -= overflow;
130 LOGINC(log->log_read, overflow);
131 }
132
133 if(log->log_size > 0 && log->log_proc_nr && !log->log_revive_alerted) {
134 /* Someone who was suspended on read can now
135 * be revived.
136 */
137 log->log_status = subread(log, log->log_iosize,
138 log->log_proc_nr, log->log_user_vir);
139 notify(log->log_source);
140 log->log_revive_alerted = 1;
141 }
142
143 if(log->log_size > 0)
144 log->log_select_ready_ops |= SEL_RD;
145
146 if(log->log_size > 0 && log->log_selected &&
147 !(log->log_select_alerted)) {
148 /* Someone(s) who was/were select()ing can now
149 * be awoken. If there was a blocking read (above),
150 * this can only happen if the blocking read didn't
151 * swallow all the data (log_size > 0).
152 */
153 if(log->log_selected & SEL_RD) {
154 notify(log->log_select_proc);
155 log->log_select_alerted = 1;
156#if LOG_DEBUG
157 printf("log notified %d\n", log->log_select_proc);
158#endif
159 }
160 }
161
162 return count;
163}
164
165/*===========================================================================*
166 * log_append *
167 *===========================================================================*/
168PUBLIC void
169log_append(char *buf, int count)
170{
171 int w = 0, skip = 0;
172
173 if(count < 1) return;
174 if(count > LOG_SIZE) skip = count - LOG_SIZE;
175 count -= skip;
176 buf += skip;
177 w = subwrite(&logdevices[0], count, SELF, (vir_bytes) buf);
178
179 if(w > 0 && w < count)
180 subwrite(&logdevices[0], count-w, SELF, (vir_bytes) buf+w);
181 return;
182}
183
184/*===========================================================================*
185 * subread *
186 *===========================================================================*/
187PRIVATE int
188subread(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir)
189{
190 char *buf;
191 int r;
192 if (count > log->log_size)
193 count = log->log_size;
194 if (log->log_read + count > LOG_SIZE)
195 count = LOG_SIZE - log->log_read;
196
197 buf = log->log_buffer + log->log_read;
198 if((r=sys_vircopy(SELF,D,(int)buf,proc_nr,D,user_vir, count)) != OK)
199 return r;
200
201 LOGINC(log->log_read, count);
202 log->log_size -= count;
203
204 return count;
205}
206
207/*===========================================================================*
208 * log_transfer *
209 *===========================================================================*/
210PRIVATE int log_transfer(proc_nr, opcode, position, iov, nr_req)
211int proc_nr; /* process doing the request */
212int opcode; /* DEV_GATHER or DEV_SCATTER */
213off_t position; /* offset on device to read or write */
214iovec_t *iov; /* pointer to read or write request vector */
215unsigned nr_req; /* length of request vector */
216{
217/* Read or write one the driver's minor devices. */
218 unsigned count;
219 vir_bytes user_vir;
220 struct device *dv;
221 unsigned long dv_size;
222 int accumulated_read = 0;
223 struct logdevice *log;
224
225 if(log_device < 0 || log_device >= NR_DEVS)
226 return EIO;
227
228 /* Get minor device number and check for /dev/null. */
229 dv = &log_geom[log_device];
230 dv_size = cv64ul(dv->dv_size);
231 log = &logdevices[log_device];
232
233 while (nr_req > 0) {
234 /* How much to transfer and where to / from. */
235 count = iov->iov_size;
236 user_vir = iov->iov_addr;
237
238 switch (log_device) {
239
240 case MINOR_KLOG:
241 if (opcode == DEV_GATHER) {
242 if (log->log_proc_nr || count < 1) {
243 /* There's already someone hanging to read, or
244 * no real I/O requested.
245 */
246 return(OK);
247 }
248
249 if (!log->log_size) {
250 if(accumulated_read)
251 return OK;
252 /* No data available; let caller block. */
253 log->log_proc_nr = proc_nr;
254 log->log_iosize = count;
255 log->log_user_vir = user_vir;
256 log->log_revive_alerted = 0;
257
258 /* Device_caller is a global in drivers library. */
259 log->log_source = device_caller;
260#if LOG_DEBUG
261 printf("blocked %d (%d)\n",
262 log->log_source, log->log_proc_nr);
263#endif
264 return(SUSPEND);
265 }
266 count = subread(log, count, proc_nr, user_vir);
267 if(count < 0) {
268 return count;
269 }
270 accumulated_read += count;
271 } else {
272 count = subwrite(log, count, proc_nr, user_vir);
273 if(count < 0)
274 return count;
275 }
276 break;
277 /* Unknown (illegal) minor device. */
278 default:
279 return(EINVAL);
280 }
281
282 /* Book the number of bytes transferred. */
283 iov->iov_addr += count;
284 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
285 }
286 return(OK);
287}
288
289/*============================================================================*
290 * log_do_open *
291 *============================================================================*/
292PRIVATE int log_do_open(dp, m_ptr)
293struct driver *dp;
294message *m_ptr;
295{
296 if (log_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
297 return(OK);
298}
299
300/*============================================================================*
301 * log_geometry *
302 *============================================================================*/
303PRIVATE void log_geometry(entry)
304struct partition *entry;
305{
306 /* take a page from the fake memory device geometry */
307 entry->heads = 64;
308 entry->sectors = 32;
309 entry->cylinders = div64u(log_geom[log_device].dv_size, SECTOR_SIZE) /
310 (entry->heads * entry->sectors);
311}
312
313/*============================================================================*
314 * log_cancel *
315 *============================================================================*/
316PRIVATE int log_cancel(dp, m_ptr)
317struct driver *dp;
318message *m_ptr;
319{
320 int d;
321 d = m_ptr->TTY_LINE;
322 if(d < 0 || d >= NR_DEVS)
323 return EINVAL;
324 logdevices[d].log_proc_nr = 0;
325 logdevices[d].log_revive_alerted = 0;
326 return(OK);
327}
328
329/*============================================================================*
330 * do_status *
331 *============================================================================*/
332PRIVATE void do_status(message *m_ptr)
333{
334 int d;
335 message m;
336
337 /* Caller has requested pending status information, which currently
338 * can be pending available select()s, or REVIVE events. One message
339 * is returned for every event, or DEV_NO_STATUS if no (more) events
340 * are to be returned.
341 */
342
343 for(d = 0; d < NR_DEVS; d++) {
344 /* Check for revive callback. */
345 if(logdevices[d].log_proc_nr && logdevices[d].log_revive_alerted
346 && logdevices[d].log_source == m_ptr->m_source) {
347 m.m_type = DEV_REVIVE;
348 m.REP_PROC_NR = logdevices[d].log_proc_nr;
349 m.REP_STATUS = logdevices[d].log_status;
350 send(m_ptr->m_source, &m);
351 logdevices[d].log_proc_nr = 0;
352 logdevices[d].log_revive_alerted = 0;
353#if LOG_DEBUG
354 printf("revived %d with %d bytes\n",
355 m.REP_PROC_NR, m.REP_STATUS);
356#endif
357 return;
358 }
359
360 /* Check for select callback. */
361 if(logdevices[d].log_selected && logdevices[d].log_select_proc == m_ptr->m_source
362 && logdevices[d].log_select_alerted) {
363 m.m_type = DEV_IO_READY;
364 m.DEV_SEL_OPS = logdevices[d].log_select_ready_ops;
365 m.DEV_MINOR = d;
366#if LOG_DEBUG
367 printf("select sending sent\n");
368#endif
369 send(m_ptr->m_source, &m);
370 logdevices[d].log_selected &= ~logdevices[d].log_select_ready_ops;
371 logdevices[d].log_select_alerted = 0;
372#if LOG_DEBUG
373 printf("select send sent\n");
374#endif
375 return;
376 }
377 }
378
379 /* No event found. */
380 m.m_type = DEV_NO_STATUS;
381 send(m_ptr->m_source, &m);
382
383 return;
384}
385
386/*============================================================================*
387 * log_signal *
388 *============================================================================*/
389PRIVATE void log_signal(dp, m_ptr)
390struct driver *dp;
391message *m_ptr;
392{
393 sigset_t sigset = m_ptr->NOTIFY_ARG;
394 if (sigismember(&sigset, SIGKMESS)) {
395 do_new_kmess(m_ptr);
396 }
397}
398
399
400/*============================================================================*
401 * log_other *
402 *============================================================================*/
403PRIVATE int log_other(dp, m_ptr)
404struct driver *dp;
405message *m_ptr;
406{
407 int r;
408
409 /* This function gets messages that the generic driver doesn't
410 * understand.
411 */
412 switch(m_ptr->m_type) {
413 case DIAGNOSTICS: {
414 r = do_diagnostics(m_ptr);
415 break;
416 }
417 case DEV_STATUS: {
418 do_status(m_ptr);
419 r = EDONTREPLY;
420 break;
421 }
422 default:
423 r = EINVAL;
424 break;
425 }
426 return r;
427}
428
429/*============================================================================*
430 * log_select *
431 *============================================================================*/
432PRIVATE int log_select(dp, m_ptr)
433struct driver *dp;
434message *m_ptr;
435{
436 int d, ready_ops = 0, ops = 0;
437 d = m_ptr->TTY_LINE;
438 if(d < 0 || d >= NR_DEVS) {
439#if LOG_DEBUG
440 printf("line %d? EINVAL\n", d);
441#endif
442 return EINVAL;
443 }
444
445 ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
446
447 /* Read blocks when there is no log. */
448 if((m_ptr->PROC_NR & SEL_RD) && logdevices[d].log_size > 0) {
449#if LOG_DEBUG
450 printf("log can read; size %d\n", logdevices[d].log_size);
451#endif
452 ready_ops |= SEL_RD; /* writes never block */
453 }
454
455 /* Write never blocks. */
456 if(m_ptr->PROC_NR & SEL_WR) ready_ops |= SEL_WR;
457
458 /* Enable select calback if no operations were
459 * ready to go, but operations were requested,
460 * and notify was enabled.
461 */
462 if((m_ptr->PROC_NR & SEL_NOTIFY) && ops && !ready_ops) {
463 logdevices[d].log_selected |= ops;
464 logdevices[d].log_select_proc = m_ptr->m_source;
465#if LOG_DEBUG
466 printf("log setting selector.\n");
467#endif
468 }
469
470#if LOG_DEBUG
471 printf("log returning ops %d\n", ready_ops);
472#endif
473
474 return(ready_ops);
475}
Note: See TracBrowser for help on using the repository browser.