log.c

Go to the documentation of this file.
00001 /* This file contains a driver for:
00002  *     /dev/klog        - system log device
00003  *
00004  * Changes:
00005  *   21 July 2005   - Support for diagnostic messages (Jorrit N. Herder)
00006  *    7 July 2005   - Created (Ben Gras)
00007  */
00008 
00009 #include "log.h"
00010 #include <sys/time.h>
00011 #include <sys/select.h>
00012 #include "../../kernel/const.h"
00013 #include "../../kernel/type.h"
00014 
00015 #define LOG_DEBUG               0       /* enable/ disable debugging */
00016 
00017 #define NR_DEVS                 1       /* number of minor devices */
00018 #define MINOR_KLOG              0       /* /dev/klog */
00019 
00020 #define LOGINC(n, i)    do { (n) = (((n) + (i)) % LOG_SIZE); } while(0)
00021 
00022 PUBLIC struct logdevice logdevices[NR_DEVS];
00023 PRIVATE struct device log_geom[NR_DEVS];        /* base and size of devices */
00024 PRIVATE int log_device = -1;                    /* current device */
00025 
00026 FORWARD _PROTOTYPE( char *log_name, (void) );
00027 FORWARD _PROTOTYPE( struct device *log_prepare, (int device) );
00028 FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, off_t position,
00029                                         iovec_t *iov, unsigned nr_req) );
00030 FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) );
00031 FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) );
00032 FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) );
00033 FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, message *m_ptr) );
00034 FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr) );
00035 FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) );
00036 FORWARD _PROTOTYPE( int subread, (struct logdevice *log, int count, int proc_nr, vir_bytes user_vir) );
00037 
00038 /* Entry points to this driver. */
00039 PRIVATE struct driver log_dtab = {
00040   log_name,     /* current device's name */
00041   log_do_open,  /* open or mount */
00042   do_nop,       /* nothing on a close */
00043   do_nop,       /* ioctl nop */
00044   log_prepare,  /* prepare for I/O on a given minor device */
00045   log_transfer, /* do the I/O */
00046   nop_cleanup,  /* no need to clean up */
00047   log_geometry, /* geometry */
00048   log_signal,   /* handle system signal */
00049   nop_alarm,    /* no alarm */
00050   log_cancel,   /* CANCEL request */
00051   log_select,   /* DEV_SELECT request */
00052   log_other,    /* Unrecognized messages */
00053   NULL          /* HW int */
00054 };
00055 
00056 extern int device_caller;
00057 
00058 /*===========================================================================*
00059  *                                 main                                      *
00060  *===========================================================================*/
00061 PUBLIC int main(void)
00062 {
00063   int i;
00064   for(i = 0; i < NR_DEVS; i++) {
00065         log_geom[i].dv_size = cvul64(LOG_SIZE);
00066         log_geom[i].dv_base = cvul64((long)logdevices[i].log_buffer);
00067         logdevices[i].log_size = logdevices[i].log_read =
00068                 logdevices[i].log_write =
00069                 logdevices[i].log_select_alerted =
00070                 logdevices[i].log_selected =
00071                 logdevices[i].log_select_ready_ops = 0;
00072         logdevices[i].log_proc_nr = 0;
00073         logdevices[i].log_revive_alerted = 0;
00074   }
00075   driver_task(&log_dtab);
00076   return(OK);
00077 }
00078 
00079 /*===========================================================================*
00080  *                               log_name                                            *
00081  *===========================================================================*/
00082 PRIVATE char *log_name()
00083 {
00084 /* Return a name for the current device. */
00085   static char name[] = "log";
00086   return name;  
00087 }
00088 
00089 /*===========================================================================*
00090  *                              log_prepare                                  *
00091  *===========================================================================*/
00092 PRIVATE struct device *log_prepare(device)
00093 int device;
00094 {
00095 /* Prepare for I/O on a device: check if the minor device number is ok. */
00096 
00097   if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
00098   log_device = device;
00099 
00100   return(&log_geom[device]);
00101 }
00102 
00103 /*===========================================================================*
00104  *                              subwrite                                             *
00105  *===========================================================================*/
00106 PRIVATE int
00107 subwrite(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir)
00108 {
00109         char *buf;
00110         int r;
00111         if (log->log_write + count > LOG_SIZE)
00112                 count = LOG_SIZE - log->log_write;
00113         buf = log->log_buffer + log->log_write;
00114 
00115         if(proc_nr == SELF) {
00116                 memcpy(buf, (char *) user_vir, count);
00117         }
00118         else {
00119                 if((r=sys_vircopy(proc_nr,D,user_vir, SELF,D,(int)buf, count)) != OK)
00120                         return r;
00121         }
00122 
00123         LOGINC(log->log_write, count);
00124         log->log_size += count;
00125 
00126         if(log->log_size > LOG_SIZE) {
00127                 int overflow;
00128                 overflow = log->log_size - LOG_SIZE;
00129                 log->log_size -= overflow;
00130                 LOGINC(log->log_read, overflow);
00131         }
00132 
00133         if(log->log_size > 0 && log->log_proc_nr && !log->log_revive_alerted) {
00134                 /* Someone who was suspended on read can now
00135                  * be revived.
00136                  */
00137                 log->log_status = subread(log, log->log_iosize,
00138                         log->log_proc_nr, log->log_user_vir);
00139                 notify(log->log_source); 
00140                 log->log_revive_alerted = 1;
00141         } 
00142 
00143         if(log->log_size > 0)
00144                 log->log_select_ready_ops |= SEL_RD;
00145 
00146         if(log->log_size > 0 && log->log_selected &&
00147           !(log->log_select_alerted)) {
00148                 /* Someone(s) who was/were select()ing can now
00149                  * be awoken. If there was a blocking read (above),
00150                  * this can only happen if the blocking read didn't
00151                  * swallow all the data (log_size > 0).
00152                  */
00153                 if(log->log_selected & SEL_RD) {
00154                         notify(log->log_select_proc);
00155                         log->log_select_alerted = 1;
00156 #if LOG_DEBUG
00157                         printf("log notified %d\n", log->log_select_proc);
00158 #endif
00159                 }
00160         }
00161 
00162         return count;
00163 }
00164 
00165 /*===========================================================================*
00166  *                              log_append                              *
00167  *===========================================================================*/
00168 PUBLIC void
00169 log_append(char *buf, int count)
00170 {
00171         int w = 0, skip = 0;
00172 
00173         if(count < 1) return;
00174         if(count > LOG_SIZE) skip = count - LOG_SIZE;
00175         count -= skip;
00176         buf += skip;
00177         w = subwrite(&logdevices[0], count, SELF, (vir_bytes) buf);
00178 
00179         if(w > 0 && w < count)
00180                 subwrite(&logdevices[0], count-w, SELF, (vir_bytes) buf+w);
00181         return;
00182 }
00183 
00184 /*===========================================================================*
00185  *                              subread                                      *
00186  *===========================================================================*/
00187 PRIVATE int
00188 subread(struct logdevice *log, int count, int proc_nr, vir_bytes user_vir)
00189 {
00190         char *buf;
00191         int r;
00192         if (count > log->log_size)
00193                 count = log->log_size;
00194         if (log->log_read + count > LOG_SIZE)
00195                 count = LOG_SIZE - log->log_read;
00196 
00197         buf = log->log_buffer + log->log_read;
00198         if((r=sys_vircopy(SELF,D,(int)buf,proc_nr,D,user_vir, count)) != OK)
00199                 return r;
00200 
00201         LOGINC(log->log_read, count);
00202         log->log_size -= count;
00203 
00204         return count;
00205 }
00206 
00207 /*===========================================================================*
00208  *                              log_transfer                                 *
00209  *===========================================================================*/
00210 PRIVATE int log_transfer(proc_nr, opcode, position, iov, nr_req)
00211 int proc_nr;                    /* process doing the request */
00212 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
00213 off_t position;                 /* offset on device to read or write */
00214 iovec_t *iov;                   /* pointer to read or write request vector */
00215 unsigned nr_req;                /* length of request vector */
00216 {
00217 /* Read or write one the driver's minor devices. */
00218   unsigned count;
00219   vir_bytes user_vir;
00220   struct device *dv;
00221   unsigned long dv_size;
00222   int accumulated_read = 0;
00223   struct logdevice *log;
00224   static int f;
00225 
00226   if(log_device < 0 || log_device >= NR_DEVS)
00227         return EIO;
00228 
00229   /* Get minor device number and check for /dev/null. */
00230   dv = &log_geom[log_device];
00231   dv_size = cv64ul(dv->dv_size);
00232   log = &logdevices[log_device];
00233 
00234   while (nr_req > 0) {
00235         /* How much to transfer and where to / from. */
00236         count = iov->iov_size;
00237         user_vir = iov->iov_addr;
00238 
00239         switch (log_device) {
00240 
00241         case MINOR_KLOG:
00242             if (opcode == DEV_GATHER) {
00243                 if (log->log_proc_nr || count < 1) {
00244                         /* There's already someone hanging to read, or
00245                          * no real I/O requested.
00246                          */
00247                         return(OK);
00248                 }
00249 
00250                 if (!log->log_size) {
00251                         if(accumulated_read)
00252                                 return OK;
00253                         /* No data available; let caller block. */
00254                         log->log_proc_nr = proc_nr;
00255                         log->log_iosize = count;
00256                         log->log_user_vir = user_vir;
00257                         log->log_revive_alerted = 0;
00258 
00259                         /* Device_caller is a global in drivers library. */
00260                         log->log_source = device_caller;
00261 #if LOG_DEBUG
00262                         printf("blocked %d (%d)\n", 
00263                                 log->log_source, log->log_proc_nr);
00264 #endif
00265                         return(SUSPEND);
00266                 }
00267                 count = subread(log, count, proc_nr, user_vir);
00268                 if(count < 0) {
00269                         return count;
00270                 }
00271                 accumulated_read += count;
00272             } else {
00273                 count = subwrite(log, count, proc_nr, user_vir);
00274                 if(count < 0)
00275                         return count;
00276             }
00277             break;
00278         /* Unknown (illegal) minor device. */
00279         default:
00280             return(EINVAL);
00281         }
00282 
00283         /* Book the number of bytes transferred. */
00284         iov->iov_addr += count;
00285         if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
00286   }
00287   return(OK);
00288 }
00289 
00290 /*============================================================================*
00291  *                              log_do_open                                   *
00292  *============================================================================*/
00293 PRIVATE int log_do_open(dp, m_ptr)
00294 struct driver *dp;
00295 message *m_ptr;
00296 {
00297   if (log_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
00298   return(OK);
00299 }
00300 
00301 /*============================================================================*
00302  *                              log_geometry                                  *
00303  *============================================================================*/
00304 PRIVATE void log_geometry(entry)
00305 struct partition *entry;
00306 {
00307   /* take a page from the fake memory device geometry */
00308   entry->heads = 64;
00309   entry->sectors = 32;
00310   entry->cylinders = div64u(log_geom[log_device].dv_size, SECTOR_SIZE) /
00311         (entry->heads * entry->sectors);
00312 }
00313 
00314 /*============================================================================*
00315  *                              log_cancel                                    *
00316  *============================================================================*/
00317 PRIVATE int log_cancel(dp, m_ptr)
00318 struct driver *dp;
00319 message *m_ptr;
00320 {
00321   int d;
00322   d = m_ptr->TTY_LINE;
00323   if(d < 0 || d >= NR_DEVS)
00324         return EINVAL;
00325   logdevices[d].log_proc_nr = 0;
00326   logdevices[d].log_revive_alerted = 0;
00327   return(OK);
00328 }
00329 
00330 /*============================================================================*
00331  *                              do_status                                     *
00332  *============================================================================*/
00333 PRIVATE void do_status(message *m_ptr)
00334 {
00335         int d; 
00336         message m;
00337 
00338         /* Caller has requested pending status information, which currently
00339          * can be pending available select()s, or REVIVE events. One message
00340          * is returned for every event, or DEV_NO_STATUS if no (more) events
00341          * are to be returned.
00342          */
00343 
00344         for(d = 0; d < NR_DEVS; d++) {
00345                 /* Check for revive callback. */
00346                 if(logdevices[d].log_proc_nr && logdevices[d].log_revive_alerted
00347                    && logdevices[d].log_source == m_ptr->m_source) {
00348                         m.m_type = DEV_REVIVE;
00349                         m.REP_ENDPT = logdevices[d].log_proc_nr;
00350                         m.REP_STATUS  = logdevices[d].log_status;
00351                         send(m_ptr->m_source, &m);
00352                         logdevices[d].log_proc_nr = 0;
00353                         logdevices[d].log_revive_alerted = 0;
00354 #if LOG_DEBUG
00355                 printf("revived %d with %d bytes\n", 
00356                         m.REP_ENDPT, m.REP_STATUS);
00357 #endif
00358                         return;
00359                 }
00360 
00361                 /* Check for select callback. */
00362                 if(logdevices[d].log_selected && logdevices[d].log_select_proc == m_ptr->m_source 
00363                         && logdevices[d].log_select_alerted) {
00364                         m.m_type = DEV_IO_READY;
00365                         m.DEV_SEL_OPS = logdevices[d].log_select_ready_ops;
00366                         m.DEV_MINOR   = d;
00367 #if LOG_DEBUG
00368                 printf("select sending sent\n");
00369 #endif
00370                         send(m_ptr->m_source, &m);
00371                         logdevices[d].log_selected &= ~logdevices[d].log_select_ready_ops;
00372                         logdevices[d].log_select_alerted = 0;
00373 #if LOG_DEBUG
00374                 printf("select send sent\n");
00375 #endif
00376                         return;
00377                 }
00378         }
00379 
00380         /* No event found. */
00381         m.m_type = DEV_NO_STATUS;
00382         send(m_ptr->m_source, &m);
00383 
00384         return;
00385 }
00386 
00387 /*============================================================================*
00388  *                              log_signal                                    *
00389  *============================================================================*/
00390 PRIVATE void log_signal(dp, m_ptr)
00391 struct driver *dp;
00392 message *m_ptr;
00393 {
00394   sigset_t sigset = m_ptr->NOTIFY_ARG;
00395   if (sigismember(&sigset, SIGKMESS)) {
00396         do_new_kmess(m_ptr);
00397   }     
00398 }
00399 
00400         
00401 /*============================================================================*
00402  *                              log_other                                     *
00403  *============================================================================*/
00404 PRIVATE int log_other(dp, m_ptr)
00405 struct driver *dp;
00406 message *m_ptr;
00407 {
00408         int r;
00409 
00410         /* This function gets messages that the generic driver doesn't
00411          * understand.
00412          */
00413         switch(m_ptr->m_type) {
00414         case DIAGNOSTICS: {
00415                 r = do_diagnostics(m_ptr);
00416                 break;
00417         }
00418         case DEV_STATUS: {
00419                 do_status(m_ptr);
00420                 r = EDONTREPLY;
00421                 break;
00422         }
00423         case NOTIFY_FROM(TTY_PROC_NR):
00424                 do_new_kmess(m_ptr);
00425                 r = EDONTREPLY;
00426                 break;
00427         default:
00428                 r = EINVAL;
00429                 break;
00430         }
00431         return r;
00432 }
00433 
00434 /*============================================================================*
00435  *                              log_select                                    *
00436  *============================================================================*/
00437 PRIVATE int log_select(dp, m_ptr)
00438 struct driver *dp;
00439 message *m_ptr;
00440 {
00441   int d, ready_ops = 0, ops = 0;
00442   d = m_ptr->TTY_LINE;
00443   if(d < 0 || d >= NR_DEVS) {
00444 #if LOG_DEBUG
00445         printf("line %d? EINVAL\n", d);
00446 #endif
00447         return EINVAL;
00448   }
00449 
00450   ops = m_ptr->IO_ENDPT & (SEL_RD|SEL_WR|SEL_ERR);
00451 
00452         /* Read blocks when there is no log. */
00453   if((m_ptr->IO_ENDPT & SEL_RD) && logdevices[d].log_size > 0) {
00454 #if LOG_DEBUG
00455         printf("log can read; size %d\n", logdevices[d].log_size);
00456 #endif
00457         ready_ops |= SEL_RD; /* writes never block */
00458  }
00459 
00460         /* Write never blocks. */
00461   if(m_ptr->IO_ENDPT & SEL_WR) ready_ops |= SEL_WR;
00462 
00463         /* Enable select calback if no operations were
00464          * ready to go, but operations were requested,
00465          * and notify was enabled.
00466          */
00467   if((m_ptr->IO_ENDPT & SEL_NOTIFY) && ops && !ready_ops) {
00468         logdevices[d].log_selected |= ops;
00469         logdevices[d].log_select_proc = m_ptr->m_source;
00470 #if LOG_DEBUG
00471         printf("log setting selector.\n");
00472 #endif
00473   }
00474 
00475 #if LOG_DEBUG
00476   printf("log returning ops %d\n", ready_ops);
00477 #endif
00478 
00479   return(ready_ops);
00480 }

Generated on Fri Apr 14 22:57:02 2006 for minix by  doxygen 1.4.6