The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/log/log.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   22 PUBLIC struct logdevice logdevices[NR_DEVS];
   23 PRIVATE struct device log_geom[NR_DEVS];        /* base and size of devices */
   24 PRIVATE int log_device = -1;                    /* current device */
   25 
   26 FORWARD _PROTOTYPE( char *log_name, (void) );
   27 FORWARD _PROTOTYPE( struct device *log_prepare, (int device) );
   28 FORWARD _PROTOTYPE( int log_transfer, (int proc_nr, int opcode, off_t position,
   29                                         iovec_t *iov, unsigned nr_req) );
   30 FORWARD _PROTOTYPE( int log_do_open, (struct driver *dp, message *m_ptr) );
   31 FORWARD _PROTOTYPE( int log_cancel, (struct driver *dp, message *m_ptr) );
   32 FORWARD _PROTOTYPE( int log_select, (struct driver *dp, message *m_ptr) );
   33 FORWARD _PROTOTYPE( void log_signal, (struct driver *dp, message *m_ptr) );
   34 FORWARD _PROTOTYPE( int log_other, (struct driver *dp, message *m_ptr) );
   35 FORWARD _PROTOTYPE( void log_geometry, (struct partition *entry) );
   36 FORWARD _PROTOTYPE( int subread, (struct logdevice *log, int count, int proc_nr, vir_bytes user_vir) );
   37 
   38 /* Entry points to this driver. */
   39 PRIVATE 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 
   56 extern int device_caller;
   57 
   58 /*===========================================================================*
   59  *                                 main                                      *
   60  *===========================================================================*/
   61 PUBLIC 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  *===========================================================================*/
   82 PRIVATE 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  *===========================================================================*/
   92 PRIVATE struct device *log_prepare(device)
   93 int 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  *===========================================================================*/
  106 PRIVATE int
  107 subwrite(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  *===========================================================================*/
  168 PUBLIC void
  169 log_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  *===========================================================================*/
  187 PRIVATE int
  188 subread(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  *===========================================================================*/
  210 PRIVATE int log_transfer(proc_nr, opcode, position, iov, nr_req)
  211 int proc_nr;                    /* process doing the request */
  212 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
  213 off_t position;                 /* offset on device to read or write */
  214 iovec_t *iov;                   /* pointer to read or write request vector */
  215 unsigned 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   static int f;
  225 
  226   if(log_device < 0 || log_device >= NR_DEVS)
  227         return EIO;
  228 
  229   /* Get minor device number and check for /dev/null. */
  230   dv = &log_geom[log_device];
  231   dv_size = cv64ul(dv->dv_size);
  232   log = &logdevices[log_device];
  233 
  234   while (nr_req > 0) {
  235         /* How much to transfer and where to / from. */
  236         count = iov->iov_size;
  237         user_vir = iov->iov_addr;
  238 
  239         switch (log_device) {
  240 
  241         case MINOR_KLOG:
  242             if (opcode == DEV_GATHER) {
  243                 if (log->log_proc_nr || count < 1) {
  244                         /* There's already someone hanging to read, or
  245                          * no real I/O requested.
  246                          */
  247                         return(OK);
  248                 }
  249 
  250                 if (!log->log_size) {
  251                         if(accumulated_read)
  252                                 return OK;
  253                         /* No data available; let caller block. */
  254                         log->log_proc_nr = proc_nr;
  255                         log->log_iosize = count;
  256                         log->log_user_vir = user_vir;
  257                         log->log_revive_alerted = 0;
  258 
  259                         /* Device_caller is a global in drivers library. */
  260                         log->log_source = device_caller;
  261 #if LOG_DEBUG
  262                         printf("blocked %d (%d)\n", 
  263                                 log->log_source, log->log_proc_nr);
  264 #endif
  265                         return(SUSPEND);
  266                 }
  267                 count = subread(log, count, proc_nr, user_vir);
  268                 if(count < 0) {
  269                         return count;
  270                 }
  271                 accumulated_read += count;
  272             } else {
  273                 count = subwrite(log, count, proc_nr, user_vir);
  274                 if(count < 0)
  275                         return count;
  276             }
  277             break;
  278         /* Unknown (illegal) minor device. */
  279         default:
  280             return(EINVAL);
  281         }
  282 
  283         /* Book the number of bytes transferred. */
  284         iov->iov_addr += count;
  285         if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
  286   }
  287   return(OK);
  288 }
  289 
  290 /*============================================================================*
  291  *                              log_do_open                                   *
  292  *============================================================================*/
  293 PRIVATE int log_do_open(dp, m_ptr)
  294 struct driver *dp;
  295 message *m_ptr;
  296 {
  297   if (log_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  298   return(OK);
  299 }
  300 
  301 /*============================================================================*
  302  *                              log_geometry                                  *
  303  *============================================================================*/
  304 PRIVATE void log_geometry(entry)
  305 struct partition *entry;
  306 {
  307   /* take a page from the fake memory device geometry */
  308   entry->heads = 64;
  309   entry->sectors = 32;
  310   entry->cylinders = div64u(log_geom[log_device].dv_size, SECTOR_SIZE) /
  311         (entry->heads * entry->sectors);
  312 }
  313 
  314 /*============================================================================*
  315  *                              log_cancel                                    *
  316  *============================================================================*/
  317 PRIVATE int log_cancel(dp, m_ptr)
  318 struct driver *dp;
  319 message *m_ptr;
  320 {
  321   int d;
  322   d = m_ptr->TTY_LINE;
  323   if(d < 0 || d >= NR_DEVS)
  324         return EINVAL;
  325   logdevices[d].log_proc_nr = 0;
  326   logdevices[d].log_revive_alerted = 0;
  327   return(OK);
  328 }
  329 
  330 /*============================================================================*
  331  *                              do_status                                     *
  332  *============================================================================*/
  333 PRIVATE void do_status(message *m_ptr)
  334 {
  335         int d; 
  336         message m;
  337 
  338         /* Caller has requested pending status information, which currently
  339          * can be pending available select()s, or REVIVE events. One message
  340          * is returned for every event, or DEV_NO_STATUS if no (more) events
  341          * are to be returned.
  342          */
  343 
  344         for(d = 0; d < NR_DEVS; d++) {
  345                 /* Check for revive callback. */
  346                 if(logdevices[d].log_proc_nr && logdevices[d].log_revive_alerted
  347                    && logdevices[d].log_source == m_ptr->m_source) {
  348                         m.m_type = DEV_REVIVE;
  349                         m.REP_PROC_NR = logdevices[d].log_proc_nr;
  350                         m.REP_STATUS  = logdevices[d].log_status;
  351                         send(m_ptr->m_source, &m);
  352                         logdevices[d].log_proc_nr = 0;
  353                         logdevices[d].log_revive_alerted = 0;
  354 #if LOG_DEBUG
  355                 printf("revived %d with %d bytes\n", 
  356                         m.REP_PROC_NR, m.REP_STATUS);
  357 #endif
  358                         return;
  359                 }
  360 
  361                 /* Check for select callback. */
  362                 if(logdevices[d].log_selected && logdevices[d].log_select_proc == m_ptr->m_source 
  363                         && logdevices[d].log_select_alerted) {
  364                         m.m_type = DEV_IO_READY;
  365                         m.DEV_SEL_OPS = logdevices[d].log_select_ready_ops;
  366                         m.DEV_MINOR   = d;
  367 #if LOG_DEBUG
  368                 printf("select sending sent\n");
  369 #endif
  370                         send(m_ptr->m_source, &m);
  371                         logdevices[d].log_selected &= ~logdevices[d].log_select_ready_ops;
  372                         logdevices[d].log_select_alerted = 0;
  373 #if LOG_DEBUG
  374                 printf("select send sent\n");
  375 #endif
  376                         return;
  377                 }
  378         }
  379 
  380         /* No event found. */
  381         m.m_type = DEV_NO_STATUS;
  382         send(m_ptr->m_source, &m);
  383 
  384         return;
  385 }
  386 
  387 /*============================================================================*
  388  *                              log_signal                                    *
  389  *============================================================================*/
  390 PRIVATE void log_signal(dp, m_ptr)
  391 struct driver *dp;
  392 message *m_ptr;
  393 {
  394   sigset_t sigset = m_ptr->NOTIFY_ARG;
  395   if (sigismember(&sigset, SIGKMESS)) {
  396         do_new_kmess(m_ptr);
  397   }     
  398 }
  399 
  400         
  401 /*============================================================================*
  402  *                              log_other                                     *
  403  *============================================================================*/
  404 PRIVATE int log_other(dp, m_ptr)
  405 struct driver *dp;
  406 message *m_ptr;
  407 {
  408         int r;
  409 
  410         /* This function gets messages that the generic driver doesn't
  411          * understand.
  412          */
  413         switch(m_ptr->m_type) {
  414         case DIAGNOSTICS: {
  415                 r = do_diagnostics(m_ptr);
  416                 break;
  417         }
  418         case DEV_STATUS: {
  419                 do_status(m_ptr);
  420                 r = EDONTREPLY;
  421                 break;
  422         }
  423         case NOTIFY_FROM(TTY_PROC_NR):
  424                 do_new_kmess(m_ptr);
  425                 r = EDONTREPLY;
  426                 break;
  427         default:
  428                 r = EINVAL;
  429                 break;
  430         }
  431         return r;
  432 }
  433 
  434 /*============================================================================*
  435  *                              log_select                                    *
  436  *============================================================================*/
  437 PRIVATE int log_select(dp, m_ptr)
  438 struct driver *dp;
  439 message *m_ptr;
  440 {
  441   int d, ready_ops = 0, ops = 0;
  442   d = m_ptr->TTY_LINE;
  443   if(d < 0 || d >= NR_DEVS) {
  444 #if LOG_DEBUG
  445         printf("line %d? EINVAL\n", d);
  446 #endif
  447         return EINVAL;
  448   }
  449 
  450   ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
  451 
  452         /* Read blocks when there is no log. */
  453   if((m_ptr->PROC_NR & SEL_RD) && logdevices[d].log_size > 0) {
  454 #if LOG_DEBUG
  455         printf("log can read; size %d\n", logdevices[d].log_size);
  456 #endif
  457         ready_ops |= SEL_RD; /* writes never block */
  458  }
  459 
  460         /* Write never blocks. */
  461   if(m_ptr->PROC_NR & SEL_WR) ready_ops |= SEL_WR;
  462 
  463         /* Enable select calback if no operations were
  464          * ready to go, but operations were requested,
  465          * and notify was enabled.
  466          */
  467   if((m_ptr->PROC_NR & SEL_NOTIFY) && ops && !ready_ops) {
  468         logdevices[d].log_selected |= ops;
  469         logdevices[d].log_select_proc = m_ptr->m_source;
  470 #if LOG_DEBUG
  471         printf("log setting selector.\n");
  472 #endif
  473   }
  474 
  475 #if LOG_DEBUG
  476   printf("log returning ops %d\n", ready_ops);
  477 #endif
  478 
  479   return(ready_ops);
  480 }

Cache object: 1ec99a269414280f4fd93e807512cfa1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.