1*433d6423SLionel Sambuc /* This file contains a driver for: 2*433d6423SLionel Sambuc * /dev/klog - system log device 3*433d6423SLionel Sambuc * 4*433d6423SLionel Sambuc * Changes: 5*433d6423SLionel Sambuc * 21 July 2005 - Support for diagnostic messages (Jorrit N. Herder) 6*433d6423SLionel Sambuc * 7 July 2005 - Created (Ben Gras) 7*433d6423SLionel Sambuc */ 8*433d6423SLionel Sambuc 9*433d6423SLionel Sambuc #include "log.h" 10*433d6423SLionel Sambuc #include <sys/time.h> 11*433d6423SLionel Sambuc #include <sys/select.h> 12*433d6423SLionel Sambuc #include <minix/endpoint.h> 13*433d6423SLionel Sambuc 14*433d6423SLionel Sambuc #define LOG_DEBUG 0 /* enable/ disable debugging */ 15*433d6423SLionel Sambuc 16*433d6423SLionel Sambuc #define NR_DEVS 1 /* number of minor devices */ 17*433d6423SLionel Sambuc #define MINOR_KLOG 0 /* /dev/klog */ 18*433d6423SLionel Sambuc 19*433d6423SLionel Sambuc #define LOGINC(n, i) do { (n) = (((n) + (i)) % LOG_SIZE); } while(0) 20*433d6423SLionel Sambuc 21*433d6423SLionel Sambuc struct logdevice logdevices[NR_DEVS]; 22*433d6423SLionel Sambuc 23*433d6423SLionel Sambuc static ssize_t log_read(devminor_t minor, u64_t position, endpoint_t endpt, 24*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 25*433d6423SLionel Sambuc static ssize_t log_write(devminor_t minor, u64_t position, endpoint_t endpt, 26*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 27*433d6423SLionel Sambuc static int log_open(devminor_t minor, int access, endpoint_t user_endpt); 28*433d6423SLionel Sambuc static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id); 29*433d6423SLionel Sambuc static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt); 30*433d6423SLionel Sambuc static int subread(struct logdevice *log, size_t size, endpoint_t endpt, 31*433d6423SLionel Sambuc cp_grant_id_t grant); 32*433d6423SLionel Sambuc 33*433d6423SLionel Sambuc /* Entry points to this driver. */ 34*433d6423SLionel Sambuc static struct chardriver log_dtab = { 35*433d6423SLionel Sambuc .cdr_open = log_open, 36*433d6423SLionel Sambuc .cdr_read = log_read, 37*433d6423SLionel Sambuc .cdr_write = log_write, 38*433d6423SLionel Sambuc .cdr_cancel = log_cancel, 39*433d6423SLionel Sambuc .cdr_select = log_select 40*433d6423SLionel Sambuc }; 41*433d6423SLionel Sambuc 42*433d6423SLionel Sambuc /* SEF functions and variables. */ 43*433d6423SLionel Sambuc static void sef_local_startup(void); 44*433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info); 45*433d6423SLionel Sambuc EXTERN int sef_cb_lu_prepare(int state); 46*433d6423SLionel Sambuc EXTERN int sef_cb_lu_state_isvalid(int state); 47*433d6423SLionel Sambuc EXTERN void sef_cb_lu_state_dump(int state); 48*433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo); 49*433d6423SLionel Sambuc 50*433d6423SLionel Sambuc /*===========================================================================* 51*433d6423SLionel Sambuc * main * 52*433d6423SLionel Sambuc *===========================================================================*/ 53*433d6423SLionel Sambuc int main(void) 54*433d6423SLionel Sambuc { 55*433d6423SLionel Sambuc /* SEF local startup. */ 56*433d6423SLionel Sambuc sef_local_startup(); 57*433d6423SLionel Sambuc 58*433d6423SLionel Sambuc /* Call the generic receive loop. */ 59*433d6423SLionel Sambuc chardriver_task(&log_dtab); 60*433d6423SLionel Sambuc 61*433d6423SLionel Sambuc return(OK); 62*433d6423SLionel Sambuc } 63*433d6423SLionel Sambuc 64*433d6423SLionel Sambuc /*===========================================================================* 65*433d6423SLionel Sambuc * sef_local_startup * 66*433d6423SLionel Sambuc *===========================================================================*/ 67*433d6423SLionel Sambuc static void sef_local_startup() 68*433d6423SLionel Sambuc { 69*433d6423SLionel Sambuc /* Register init callbacks. */ 70*433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh); 71*433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init_fresh); 72*433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init_fresh); 73*433d6423SLionel Sambuc 74*433d6423SLionel Sambuc /* Register live update callbacks. */ 75*433d6423SLionel Sambuc sef_setcb_lu_prepare(sef_cb_lu_prepare); 76*433d6423SLionel Sambuc sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid); 77*433d6423SLionel Sambuc sef_setcb_lu_state_dump(sef_cb_lu_state_dump); 78*433d6423SLionel Sambuc 79*433d6423SLionel Sambuc /* Register signal callbacks. */ 80*433d6423SLionel Sambuc sef_setcb_signal_handler(sef_cb_signal_handler); 81*433d6423SLionel Sambuc 82*433d6423SLionel Sambuc /* Let SEF perform startup. */ 83*433d6423SLionel Sambuc sef_startup(); 84*433d6423SLionel Sambuc } 85*433d6423SLionel Sambuc 86*433d6423SLionel Sambuc /*===========================================================================* 87*433d6423SLionel Sambuc * sef_cb_init_fresh * 88*433d6423SLionel Sambuc *===========================================================================*/ 89*433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 90*433d6423SLionel Sambuc { 91*433d6423SLionel Sambuc /* Initialize the log driver. */ 92*433d6423SLionel Sambuc int i; 93*433d6423SLionel Sambuc 94*433d6423SLionel Sambuc /* Initialize log devices. */ 95*433d6423SLionel Sambuc for(i = 0; i < NR_DEVS; i++) { 96*433d6423SLionel Sambuc logdevices[i].log_size = logdevices[i].log_read = 97*433d6423SLionel Sambuc logdevices[i].log_write = 98*433d6423SLionel Sambuc logdevices[i].log_selected = 0; 99*433d6423SLionel Sambuc logdevices[i].log_source = NONE; 100*433d6423SLionel Sambuc } 101*433d6423SLionel Sambuc 102*433d6423SLionel Sambuc /* Register for diagnostics notifications. */ 103*433d6423SLionel Sambuc sys_diagctl_register(); 104*433d6423SLionel Sambuc 105*433d6423SLionel Sambuc return(OK); 106*433d6423SLionel Sambuc } 107*433d6423SLionel Sambuc 108*433d6423SLionel Sambuc /*===========================================================================* 109*433d6423SLionel Sambuc * sef_cb_signal_handler * 110*433d6423SLionel Sambuc *===========================================================================*/ 111*433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo) 112*433d6423SLionel Sambuc { 113*433d6423SLionel Sambuc /* Only check for a pending message from the kernel, ignore anything else. */ 114*433d6423SLionel Sambuc if (signo != SIGKMESS) return; 115*433d6423SLionel Sambuc 116*433d6423SLionel Sambuc do_new_kmess(); 117*433d6423SLionel Sambuc } 118*433d6423SLionel Sambuc 119*433d6423SLionel Sambuc /*===========================================================================* 120*433d6423SLionel Sambuc * subwrite * 121*433d6423SLionel Sambuc *===========================================================================*/ 122*433d6423SLionel Sambuc static int 123*433d6423SLionel Sambuc subwrite(struct logdevice *log, size_t size, endpoint_t endpt, 124*433d6423SLionel Sambuc cp_grant_id_t grant, char *localbuf) 125*433d6423SLionel Sambuc { 126*433d6423SLionel Sambuc size_t count, offset; 127*433d6423SLionel Sambuc int overflow, r; 128*433d6423SLionel Sambuc devminor_t minor; 129*433d6423SLionel Sambuc char *buf; 130*433d6423SLionel Sambuc message m; 131*433d6423SLionel Sambuc 132*433d6423SLionel Sambuc /* With a sufficiently large input size, we might wrap around the ring buffer 133*433d6423SLionel Sambuc * multiple times. 134*433d6423SLionel Sambuc */ 135*433d6423SLionel Sambuc for (offset = 0; offset < size; offset += count) { 136*433d6423SLionel Sambuc count = size - offset; 137*433d6423SLionel Sambuc 138*433d6423SLionel Sambuc if (log->log_write + count > LOG_SIZE) 139*433d6423SLionel Sambuc count = LOG_SIZE - log->log_write; 140*433d6423SLionel Sambuc buf = log->log_buffer + log->log_write; 141*433d6423SLionel Sambuc 142*433d6423SLionel Sambuc if(localbuf != NULL) { 143*433d6423SLionel Sambuc memcpy(buf, localbuf, count); 144*433d6423SLionel Sambuc localbuf += count; 145*433d6423SLionel Sambuc } 146*433d6423SLionel Sambuc else { 147*433d6423SLionel Sambuc if((r=sys_safecopyfrom(endpt, grant, offset, 148*433d6423SLionel Sambuc (vir_bytes)buf, count)) != OK) 149*433d6423SLionel Sambuc break; /* do process partial write upon error */ 150*433d6423SLionel Sambuc } 151*433d6423SLionel Sambuc 152*433d6423SLionel Sambuc LOGINC(log->log_write, count); 153*433d6423SLionel Sambuc log->log_size += count; 154*433d6423SLionel Sambuc 155*433d6423SLionel Sambuc if(log->log_size > LOG_SIZE) { 156*433d6423SLionel Sambuc overflow = log->log_size - LOG_SIZE; 157*433d6423SLionel Sambuc log->log_size -= overflow; 158*433d6423SLionel Sambuc LOGINC(log->log_read, overflow); 159*433d6423SLionel Sambuc } 160*433d6423SLionel Sambuc 161*433d6423SLionel Sambuc r = offset; /* this will be the return value upon success */ 162*433d6423SLionel Sambuc } 163*433d6423SLionel Sambuc 164*433d6423SLionel Sambuc if (log->log_size > 0 && log->log_source != NONE) { 165*433d6423SLionel Sambuc /* Someone who was suspended on read can now be revived. */ 166*433d6423SLionel Sambuc r = subread(log, log->log_iosize, log->log_source, log->log_grant); 167*433d6423SLionel Sambuc 168*433d6423SLionel Sambuc chardriver_reply_task(log->log_source, log->log_id, r); 169*433d6423SLionel Sambuc 170*433d6423SLionel Sambuc log->log_source = NONE; 171*433d6423SLionel Sambuc } 172*433d6423SLionel Sambuc 173*433d6423SLionel Sambuc if (log->log_size > 0 && (log->log_selected & CDEV_OP_RD)) { 174*433d6423SLionel Sambuc /* Someone(s) who was/were select()ing can now be awoken. If there was 175*433d6423SLionel Sambuc * a blocking read (above), this can only happen if the blocking read 176*433d6423SLionel Sambuc * didn't swallow all the data (log_size > 0). 177*433d6423SLionel Sambuc */ 178*433d6423SLionel Sambuc minor = log-logdevices; 179*433d6423SLionel Sambuc #if LOG_DEBUG 180*433d6423SLionel Sambuc printf("select sending CDEV_SEL2_REPLY\n"); 181*433d6423SLionel Sambuc #endif 182*433d6423SLionel Sambuc chardriver_reply_select(log->log_select_proc, minor, CDEV_OP_RD); 183*433d6423SLionel Sambuc log->log_selected &= ~CDEV_OP_RD; 184*433d6423SLionel Sambuc } 185*433d6423SLionel Sambuc 186*433d6423SLionel Sambuc return r; 187*433d6423SLionel Sambuc } 188*433d6423SLionel Sambuc 189*433d6423SLionel Sambuc /*===========================================================================* 190*433d6423SLionel Sambuc * log_append * 191*433d6423SLionel Sambuc *===========================================================================*/ 192*433d6423SLionel Sambuc void 193*433d6423SLionel Sambuc log_append(char *buf, int count) 194*433d6423SLionel Sambuc { 195*433d6423SLionel Sambuc int skip = 0; 196*433d6423SLionel Sambuc 197*433d6423SLionel Sambuc if(count < 1) return; 198*433d6423SLionel Sambuc if(count > LOG_SIZE) skip = count - LOG_SIZE; 199*433d6423SLionel Sambuc count -= skip; 200*433d6423SLionel Sambuc buf += skip; 201*433d6423SLionel Sambuc 202*433d6423SLionel Sambuc subwrite(&logdevices[0], count, SELF, GRANT_INVALID, buf); 203*433d6423SLionel Sambuc } 204*433d6423SLionel Sambuc 205*433d6423SLionel Sambuc /*===========================================================================* 206*433d6423SLionel Sambuc * subread * 207*433d6423SLionel Sambuc *===========================================================================*/ 208*433d6423SLionel Sambuc static int 209*433d6423SLionel Sambuc subread(struct logdevice *log, size_t size, endpoint_t endpt, 210*433d6423SLionel Sambuc cp_grant_id_t grant) 211*433d6423SLionel Sambuc { 212*433d6423SLionel Sambuc size_t offset, count; 213*433d6423SLionel Sambuc char *buf; 214*433d6423SLionel Sambuc int r; 215*433d6423SLionel Sambuc 216*433d6423SLionel Sambuc for (offset = 0; log->log_size > 0 && offset < size; offset += count) { 217*433d6423SLionel Sambuc count = size - offset; 218*433d6423SLionel Sambuc 219*433d6423SLionel Sambuc if (count > log->log_size) 220*433d6423SLionel Sambuc count = log->log_size; 221*433d6423SLionel Sambuc if (log->log_read + count > LOG_SIZE) 222*433d6423SLionel Sambuc count = LOG_SIZE - log->log_read; 223*433d6423SLionel Sambuc 224*433d6423SLionel Sambuc buf = log->log_buffer + log->log_read; 225*433d6423SLionel Sambuc if((r=sys_safecopyto(endpt, grant, offset, (vir_bytes)buf, 226*433d6423SLionel Sambuc count)) != OK) 227*433d6423SLionel Sambuc return r; 228*433d6423SLionel Sambuc 229*433d6423SLionel Sambuc LOGINC(log->log_read, count); 230*433d6423SLionel Sambuc log->log_size -= count; 231*433d6423SLionel Sambuc } 232*433d6423SLionel Sambuc 233*433d6423SLionel Sambuc return offset; 234*433d6423SLionel Sambuc } 235*433d6423SLionel Sambuc 236*433d6423SLionel Sambuc /*===========================================================================* 237*433d6423SLionel Sambuc * log_read * 238*433d6423SLionel Sambuc *===========================================================================*/ 239*433d6423SLionel Sambuc static ssize_t log_read(devminor_t minor, u64_t UNUSED(position), 240*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags, 241*433d6423SLionel Sambuc cdev_id_t id) 242*433d6423SLionel Sambuc { 243*433d6423SLionel Sambuc /* Read from one of the driver's minor devices. */ 244*433d6423SLionel Sambuc struct logdevice *log; 245*433d6423SLionel Sambuc int r; 246*433d6423SLionel Sambuc 247*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS) return EIO; 248*433d6423SLionel Sambuc log = &logdevices[minor]; 249*433d6423SLionel Sambuc 250*433d6423SLionel Sambuc /* If there's already someone hanging to read, don't accept new work. */ 251*433d6423SLionel Sambuc if (log->log_source != NONE) return OK; 252*433d6423SLionel Sambuc 253*433d6423SLionel Sambuc if (!log->log_size && size > 0) { 254*433d6423SLionel Sambuc if (flags & CDEV_NONBLOCK) return EAGAIN; 255*433d6423SLionel Sambuc 256*433d6423SLionel Sambuc /* No data available; let caller block. */ 257*433d6423SLionel Sambuc log->log_source = endpt; 258*433d6423SLionel Sambuc log->log_iosize = size; 259*433d6423SLionel Sambuc log->log_grant = grant; 260*433d6423SLionel Sambuc log->log_id = id; 261*433d6423SLionel Sambuc #if LOG_DEBUG 262*433d6423SLionel Sambuc printf("blocked %d (%d)\n", log->log_source, id); 263*433d6423SLionel Sambuc #endif 264*433d6423SLionel Sambuc return EDONTREPLY; 265*433d6423SLionel Sambuc } 266*433d6423SLionel Sambuc 267*433d6423SLionel Sambuc return subread(log, size, endpt, grant); 268*433d6423SLionel Sambuc } 269*433d6423SLionel Sambuc 270*433d6423SLionel Sambuc /*===========================================================================* 271*433d6423SLionel Sambuc * log_write * 272*433d6423SLionel Sambuc *===========================================================================*/ 273*433d6423SLionel Sambuc static ssize_t log_write(devminor_t minor, u64_t UNUSED(position), 274*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), 275*433d6423SLionel Sambuc cdev_id_t UNUSED(id)) 276*433d6423SLionel Sambuc { 277*433d6423SLionel Sambuc /* Write to one of the driver's minor devices. */ 278*433d6423SLionel Sambuc struct logdevice *log; 279*433d6423SLionel Sambuc int r; 280*433d6423SLionel Sambuc 281*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS) return EIO; 282*433d6423SLionel Sambuc log = &logdevices[minor]; 283*433d6423SLionel Sambuc 284*433d6423SLionel Sambuc return subwrite(log, size, endpt, grant, NULL); 285*433d6423SLionel Sambuc } 286*433d6423SLionel Sambuc 287*433d6423SLionel Sambuc /*============================================================================* 288*433d6423SLionel Sambuc * log_open * 289*433d6423SLionel Sambuc *============================================================================*/ 290*433d6423SLionel Sambuc static int log_open(devminor_t minor, int UNUSED(access), 291*433d6423SLionel Sambuc endpoint_t UNUSED(user_endpt)) 292*433d6423SLionel Sambuc { 293*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS) return(ENXIO); 294*433d6423SLionel Sambuc 295*433d6423SLionel Sambuc return(OK); 296*433d6423SLionel Sambuc } 297*433d6423SLionel Sambuc 298*433d6423SLionel Sambuc /*============================================================================* 299*433d6423SLionel Sambuc * log_cancel * 300*433d6423SLionel Sambuc *============================================================================*/ 301*433d6423SLionel Sambuc static int log_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) 302*433d6423SLionel Sambuc { 303*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS) 304*433d6423SLionel Sambuc return EINVAL; 305*433d6423SLionel Sambuc 306*433d6423SLionel Sambuc /* Not for the suspended request? Must be a stale cancel request. Ignore. */ 307*433d6423SLionel Sambuc if (logdevices[minor].log_source != endpt || logdevices[minor].log_id != id) 308*433d6423SLionel Sambuc return EDONTREPLY; 309*433d6423SLionel Sambuc 310*433d6423SLionel Sambuc logdevices[minor].log_source = NONE; 311*433d6423SLionel Sambuc 312*433d6423SLionel Sambuc return EINTR; /* this is the reply to the original, interrupted request */ 313*433d6423SLionel Sambuc } 314*433d6423SLionel Sambuc 315*433d6423SLionel Sambuc /*============================================================================* 316*433d6423SLionel Sambuc * log_select * 317*433d6423SLionel Sambuc *============================================================================*/ 318*433d6423SLionel Sambuc static int log_select(devminor_t minor, unsigned int ops, endpoint_t endpt) 319*433d6423SLionel Sambuc { 320*433d6423SLionel Sambuc int want_ops, ready_ops = 0; 321*433d6423SLionel Sambuc 322*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS) 323*433d6423SLionel Sambuc return ENXIO; 324*433d6423SLionel Sambuc 325*433d6423SLionel Sambuc want_ops = ops & (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); 326*433d6423SLionel Sambuc 327*433d6423SLionel Sambuc /* Read blocks when there is no log. */ 328*433d6423SLionel Sambuc if ((want_ops & CDEV_OP_RD) && logdevices[minor].log_size > 0) { 329*433d6423SLionel Sambuc #if LOG_DEBUG 330*433d6423SLionel Sambuc printf("log can read; size %d\n", logdevices[minor].log_size); 331*433d6423SLionel Sambuc #endif 332*433d6423SLionel Sambuc ready_ops |= CDEV_OP_RD; 333*433d6423SLionel Sambuc } 334*433d6423SLionel Sambuc 335*433d6423SLionel Sambuc /* Write never blocks. */ 336*433d6423SLionel Sambuc if (want_ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR; 337*433d6423SLionel Sambuc 338*433d6423SLionel Sambuc /* Enable select calback if not all requested operations were ready to go, 339*433d6423SLionel Sambuc * and notify was enabled. 340*433d6423SLionel Sambuc */ 341*433d6423SLionel Sambuc want_ops &= ~ready_ops; 342*433d6423SLionel Sambuc if ((ops & CDEV_NOTIFY) && want_ops) { 343*433d6423SLionel Sambuc logdevices[minor].log_selected |= want_ops; 344*433d6423SLionel Sambuc logdevices[minor].log_select_proc = endpt; 345*433d6423SLionel Sambuc #if LOG_DEBUG 346*433d6423SLionel Sambuc printf("log setting selector.\n"); 347*433d6423SLionel Sambuc #endif 348*433d6423SLionel Sambuc } 349*433d6423SLionel Sambuc 350*433d6423SLionel Sambuc #if LOG_DEBUG 351*433d6423SLionel Sambuc printf("log returning ops %d\n", ready_ops); 352*433d6423SLionel Sambuc #endif 353*433d6423SLionel Sambuc 354*433d6423SLionel Sambuc return(ready_ops); 355*433d6423SLionel Sambuc } 356