1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/sysmacros.h> 30 #include <sys/callb.h> 31 #include <sys/fcntl.h> 32 #include <sys/filio.h> 33 #include <sys/pathname.h> 34 #include <sys/cpuvar.h> 35 #include <sys/promif.h> 36 #include <fs/sockfs/nl7c.h> 37 #include <fs/sockfs/nl7curi.h> 38 39 #include <inet/nca/ncadoorhdr.h> 40 #include <inet/nca/ncalogd.h> 41 42 extern boolean_t nl7c_logd_enabled; 43 extern boolean_t nl7c_logd_started; 44 extern boolean_t nl7c_logd_cycle; 45 46 extern void nl7clogd_startup(void); 47 48 extern boolean_t nl7c_http_log(uri_desc_t *, uri_desc_t *, 49 nca_request_log_t *, char **, char **, uint32_t *); 50 51 static void logit_flush(void *); 52 53 /* 54 * NL7C reuses the NCA logging scheme, the directory "/var/nca" contains 55 * the symlink "current" to 1 of up to 16 NCA BLF logging files, by default 56 * a single logging file "log", optionally paths of up to 16 log files can 57 * be specified via ncalogd.conf(4), note that these log files need not be 58 * in the "/var/nca" directory. 59 * 60 * NL7C reuses the NCA logging APIs defined in <inet/nca/ncalogd.h>, at 61 * some future date (when NCA is depricated or improvements are needed) 62 * these need to be moved into NL7C. 63 * 64 * NL7C implements logging differently in 2 ways, 1st the initialization 65 * is handled completely in the kernel by NL7C when it's enabled vs NCA 66 * when the kmod was loaded, 2nd a simple worker thread with a FIFO queue 67 * is used to process log_buf_t's instead of a squeue_t (this is done as 68 * squeue_t's are private to NCA and IP at some future date we may us an 69 * IP squeue_t): 70 * 71 * logd_t - used by various functions to manage a singly linked 72 * grounded list of log_buf_t's and it's worker thread. 73 */ 74 75 typedef struct logd_s { 76 log_buf_t *head; 77 log_buf_t *tail; 78 kthread_t *worker; 79 kcondvar_t wait; 80 kmutex_t lock; 81 } logd_t; 82 83 /* 84 * In-kernel logging: 85 * 86 * nl7c_logbuf_max - tunable for the number of preallocated next 87 * log_buf_t(s) for use by log_buf_alloc(), note if the value is 88 * 0 (the default) then max_cpus worth will be allocated. 89 * 90 * logd - global logd_t used to post log_buf_t's too. 91 * 92 * log - global current log_buf_t that logit() logs too. 93 * 94 * logv[] - vector of available next logbuf(s) such that when 95 * logbuf is filled another can be used while being processed by 96 * the logger() and kmem_cache_alloc() of a replacement is done. 97 * 98 * logvcnt - count of logv[] vector element(s) and the index 99 * plus 1 of the next logbuf. 100 * 101 * log_buf_kmc - the kmem_cache to alloc/free log_buf_t's from/to. 102 * 103 * fio - the global nca_fio_t used to manage file i/o to a logfile. 104 * 105 * dir - path to the directory where the current logfile symlink 106 * is created and the default directory for logfile(s). 107 * 108 * symlink - name of the logfile symlink. 109 * 110 * symlink_path - path to the logfile symlink. 111 * 112 * log_lock - the kmutex_t used to guarantee atomic access of 113 * all of the above. 114 * 115 * flush_tid - logit_flush() timeout id. 116 * 117 * LOGBUFV_ALLOC() - macro used to add log_buf_t(s) to logv[]. 118 */ 119 120 int nl7c_logbuf_max = 0; 121 static logd_t logd; 122 static log_buf_t *log = NULL; 123 static log_buf_t **logv = NULL; 124 static int logvcnt = 0; 125 static kmem_cache_t *log_buf_kmc; 126 static nca_fio_t fio; 127 static caddr_t dir = "/var/nca/"; 128 static caddr_t symlink = "current"; 129 static caddr_t symlink_dir = "/var/nca"; 130 static caddr_t symlink_path = "/var/nca/current"; 131 132 static kmutex_t log_lock; 133 134 static timeout_id_t flush_tid; 135 136 #define LOGBUFV_ALLOC(kmflag) { \ 137 log_buf_t *_p; \ 138 \ 139 ASSERT(mutex_owned(&log_lock)); \ 140 while (logvcnt < nl7c_logbuf_max) { \ 141 /*CONSTCOND*/ \ 142 if (kmflag == KM_SLEEP) \ 143 mutex_exit(&log_lock); \ 144 _p = kmem_cache_alloc(log_buf_kmc, kmflag); \ 145 /*CONSTCOND*/ \ 146 if (kmflag == KM_SLEEP) { \ 147 mutex_enter(&log_lock); \ 148 if (logvcnt == nl7c_logbuf_max) { \ 149 mutex_exit(&log_lock); \ 150 kmem_cache_free(log_buf_kmc, _p); \ 151 mutex_enter(&log_lock); \ 152 break; \ 153 } \ 154 } else { \ 155 if (_p == NULL) { \ 156 break; \ 157 } \ 158 } \ 159 logv[logvcnt++] = _p; \ 160 } \ 161 } 162 163 /* 164 * Exports for inet/nca/ncaddi.c: 165 */ 166 167 nca_fio_t *nl7c_logd_fio = &fio; 168 169 static void 170 log_buf_alloc(int kmflag) 171 { 172 nca_log_buf_hdr_t *hdr; 173 static ulong_t seq = 0; 174 175 ASSERT(mutex_owned(&log_lock)); 176 177 if (logvcnt == 0) { 178 /* 179 * No logv[] to use for the new log global logbuf, 180 * try to allocate one or more before giving up. 181 */ 182 LOGBUFV_ALLOC(kmflag); 183 if (logvcnt == 0) { 184 /* No joy, just give up. */ 185 log = NULL; 186 return; 187 } 188 } 189 log = logv[--logvcnt]; 190 191 log->size = NCA_DEFAULT_LOG_BUF_SIZE; 192 log->cur_pos = sizeof (*hdr); 193 194 hdr = (nca_log_buf_hdr_t *)&log->buffer; 195 hdr->nca_loghdr.nca_version = NCA_LOG_VERSION1; 196 hdr->nca_loghdr.nca_op = log_op; 197 hdr->nca_logstats.n_log_size = NCA_DEFAULT_LOG_BUF_SIZE - sizeof (*hdr); 198 hdr->nca_logstats.n_log_recs = 0; 199 hdr->nca_logstats.n_log_upcall = seq++; 200 201 /* Try to allocate for at least the one we just used */ 202 LOGBUFV_ALLOC(kmflag); 203 } 204 205 static void 206 logd_off() 207 { 208 ; 209 } 210 211 static void 212 logd_log_write(kmutex_t *lock, log_buf_t *lbp) 213 { 214 nca_log_buf_hdr_t *hdr = (nca_log_buf_hdr_t *)lbp->buffer; 215 nca_log_stat_t *sts = &hdr->nca_logstats; 216 int size = sts->n_log_size + sizeof (*hdr); 217 vnode_t *vp; 218 uio_t uio; 219 iovec_t iov; 220 int ret; 221 boolean_t noretry = B_FALSE; 222 vattr_t attr; 223 224 if (size & (DEV_BSIZE - 1)) { 225 /* 226 * Not appropriately sized for directio(), 227 * add some filler so it is. 228 */ 229 sts->n_log_size += DEV_BSIZE - (size & (DEV_BSIZE - 1)); 230 size = sts->n_log_size + sizeof (*hdr); 231 } 232 retry: 233 if (nca_fio_offset(&fio) + size <= nca_fio_size(&fio)) { 234 /* 235 * Room in the current log file so write the logbuf out, 236 * exit the logd lock while doing the i/o as to not block 237 * queuing. 238 */ 239 mutex_exit(lock); 240 241 vp = nca_fio_vp(&fio); 242 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 243 iov.iov_base = lbp->buffer; 244 iov.iov_len = size; 245 uio.uio_iov = &iov; 246 uio.uio_iovcnt = 1; 247 uio.uio_segflg = UIO_SYSSPACE; 248 uio.uio_fmode = 0; 249 uio.uio_loffset = (u_offset_t)nca_fio_offset(&fio); 250 uio.uio_llimit = curproc->p_fsz_ctl; 251 uio.uio_resid = size; 252 ret = VOP_WRITE(vp, &uio, 0, kcred, NULL); 253 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 254 if (ret != 0) { 255 if (ret == EFBIG) { 256 /* 257 * Out of space for this file, 258 * retry with the next. 259 */ 260 nca_fio_size(&fio) = nca_fio_offset(&fio); 261 if (noretry) { 262 nl7c_logd_enabled = B_FALSE; 263 goto done; 264 } else 265 goto next; 266 } 267 } 268 nca_fio_offset(&fio) = uio.uio_loffset; 269 270 mutex_enter(lock); 271 goto done; 272 } 273 274 /* 275 * Current logfile doesn't have sufficient space 276 * so move on to next file (if any). 277 */ 278 next: 279 mutex_exit(lock); 280 /* Close current file */ 281 ret = VOP_CLOSE(nca_fio_vp(&fio), FCREAT|FWRITE|FAPPEND|FTRUNC, 282 1, (offset_t)0, kcred); 283 nca_fio_vp(&fio) = NULL; 284 if (ret) { 285 cmn_err(CE_WARN, "nl7c_logd: close of %s failed (error %d)", 286 nca_fio_name(&fio), ret); 287 nl7c_logd_enabled = B_FALSE; 288 logd_off(); 289 return; 290 } 291 292 /* Go to next file */ 293 nca_fio_ix(&fio)++; 294 if (nca_fio_ix(&fio) == nca_fio_cnt(&fio)) { 295 /* 296 * We have reached the last file. If cycling 297 * is not on, disable logging and bailout. 298 */ 299 if (nl7c_logd_cycle) { 300 /* Start from the first file */ 301 nca_fio_ix(&fio) = 0; 302 } else { 303 nca_fio_ix(&fio)--; 304 nl7c_logd_enabled = B_FALSE; 305 logd_off(); 306 return; 307 } 308 } 309 310 /* Open the next log file */ 311 ret = vn_open(nca_fio_name(&fio), UIO_SYSSPACE, FCREAT|FWRITE|FTRUNC, 312 0600, &nca_fio_vp(&fio), 0, 0); 313 if (ret) { 314 cmn_err(CE_WARN, "nl7c_logd: vn_open of %s failed (error %d)", 315 nca_fio_name(&fio), ret); 316 nl7c_logd_enabled = B_FALSE; 317 logd_off(); 318 return; 319 } 320 321 /* Turn on directio */ 322 (void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO, 323 DIRECTIO_ON, 0, kcred, NULL); 324 325 /* Start writing from the begining of the file */ 326 nca_fio_offset(&fio) = 0; 327 328 /* Remove the current symlink */ 329 (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred); 330 331 attr.va_mask = AT_MODE | AT_TYPE; 332 attr.va_mode = 0777; 333 attr.va_type = VLNK; 334 335 /* Create symlink to the new log file */ 336 ret = VOP_SYMLINK(nca_fio_dvp(&fio), symlink, 337 &attr, nca_fio_name(&fio), kcred); 338 if (ret) { 339 cmn_err(CE_WARN, "nl7c_logd: symlink of %s to %s failed", 340 symlink, nca_fio_name(&fio)); 341 nl7c_logd_enabled = B_FALSE; 342 logd_off(); 343 return; 344 } 345 mutex_enter(lock); 346 goto retry; 347 348 done: 349 if (logvcnt < nl7c_logbuf_max) { 350 /* May need to allocate some logbuf(s) for logv[] */ 351 mutex_enter(&log_lock); 352 if (logvcnt < nl7c_logbuf_max) { 353 /* 354 * After acquiring the lock still need logbuf(s), 355 * if the global logbuf pointer is NULL then call 356 * log_buf_alloc() as it will fill up logbugv[] 357 * and initialize a new logbuf else fill up just 358 * the logv[] here. 359 */ 360 if (log == NULL) { 361 log_buf_alloc(KM_SLEEP); 362 } else { 363 /*LINTED*/ 364 LOGBUFV_ALLOC(KM_SLEEP); 365 } 366 } 367 mutex_exit(&log_lock); 368 } 369 } 370 371 static void 372 logd_worker(logd_t *logdp) 373 { 374 log_buf_t *lbp; 375 kmutex_t *lock = &logdp->lock; 376 kcondvar_t *wait = &logdp->wait; 377 callb_cpr_t cprinfo; 378 379 CALLB_CPR_INIT(&cprinfo, lock, callb_generic_cpr, "nl7c"); 380 mutex_enter(lock); 381 382 for (;;) { 383 /* Wait for something to do */ 384 while ((lbp = logdp->head) == NULL) { 385 CALLB_CPR_SAFE_BEGIN(&cprinfo); 386 cv_wait(wait, lock); 387 CALLB_CPR_SAFE_END(&cprinfo, lock); 388 } 389 if ((logdp->head = lbp->next) == NULL) 390 logdp->tail = NULL; 391 /* Got a logbuf to write out */ 392 if (nl7c_logd_enabled) 393 logd_log_write(lock, lbp); 394 kmem_cache_free(log_buf_kmc, lbp); 395 } 396 } 397 398 boolean_t 399 nl7c_logd_init(int fsz, caddr_t *fnv) 400 { 401 vnode_t *dvp; 402 vnode_t *svp; 403 vnode_t *vp; 404 int ret; 405 caddr_t *fnp; 406 vattr_t attr; 407 uio_t uio; 408 iovec_t iov; 409 char fbuf[TYPICALMAXPATHLEN + 1]; 410 411 /* 412 * Initialize the global logfio. 413 */ 414 nca_fio_cnt(&fio) = 0; 415 nca_fio_ix(&fio) = 0; 416 fnp = fnv; 417 while (*fnp != NULL) { 418 nca_fio_cnt(&fio)++; 419 nca_fio_name(&fio) = *fnp; 420 nca_fio_size(&fio) = fsz; 421 nca_fio_offset(&fio) = 0; 422 nca_fio_file(&fio) = nca_fio_ix(&fio); 423 nca_fio_vp(&fio) = NULL; 424 425 if (++fnp == &fnv[NCA_FIOV_SZ]) 426 break; 427 428 nca_fio_ix(&fio)++; 429 } 430 /* 431 * See if we can start logging from where we left off last time, 432 * first check if the symlink exists. 433 */ 434 dvp = NULL; 435 ret = lookupname(symlink_path, UIO_SYSSPACE, NO_FOLLOW, &dvp, &svp); 436 if (ret || dvp == NULL || svp == NULL) { 437 if (dvp == NULL) { 438 /* No NCA symlink directory, create one */ 439 attr.va_mask = AT_MODE | AT_TYPE; 440 attr.va_mode = 0755; 441 attr.va_type = VDIR; 442 ret = vn_create(symlink_dir, UIO_SYSSPACE, &attr, 443 EXCL, 0, &dvp, CRMKDIR, 0, 0); 444 if (ret) { 445 cmn_err(CE_WARN, "nl7c_logd_init: create" 446 " symlink dir of %s failed(%d).", 447 symlink_dir, ret); 448 goto error; 449 } 450 nca_fio_dvp(&fio) = dvp; 451 } 452 /* No symlink so don't know were to start from */ 453 goto fresh_start; 454 } 455 /* Save the symlink dir vnode */ 456 nca_fio_dvp(&fio) = dvp; 457 458 /* Check if the file pointed by the symlink exists */ 459 ret = lookupname(symlink_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 460 if (ret || vp == NULL) 461 goto fresh_start; 462 VN_RELE(vp); 463 464 /* Read the symlink and find it in fnv[], else fresh start */ 465 iov.iov_len = TYPICALMAXPATHLEN; 466 iov.iov_base = fbuf; 467 uio.uio_iov = &iov; 468 uio.uio_iovcnt = 1; 469 uio.uio_resid = iov.iov_len; 470 uio.uio_segflg = UIO_SYSSPACE; 471 uio.uio_loffset = 0; 472 uio.uio_fmode = 0; 473 ret = VOP_READLINK(svp, &uio, kcred); 474 if (ret) { 475 (void) VOP_REMOVE(dvp, symlink, kcred); 476 goto fresh_start; 477 } 478 479 /* Null terminate the buf */ 480 fbuf[TYPICALMAXPATHLEN - (int)uio.uio_resid] = '\0'; 481 fnp = fnv; 482 nca_fio_ix(&fio) = 0; 483 while (*fnp != NULL) { 484 if (strcmp(*fnp, fbuf) == 0) 485 break; 486 if (++fnp == &fnv[NCA_FIOV_SZ]) 487 goto fresh_start; 488 nca_fio_ix(&fio)++; 489 } 490 if (*fnp == NULL) 491 goto fresh_start; 492 493 /* Start writing to the end of the file */ 494 ret = vn_open(*fnp, UIO_SYSSPACE, 495 FCREAT|FWRITE|FAPPEND, 0600, &vp, 0, 0); 496 if (ret) { 497 cmn_err(CE_WARN, "nl7c_logd_init: vn_open of " 498 "%s failed (error %d)", *fnp, ret); 499 goto error; 500 } 501 nca_fio_vp(&fio) = vp; 502 (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL); 503 attr.va_mask = AT_SIZE; 504 ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, 0); 505 if (ret) { 506 cmn_err(CE_WARN, "nl7c_logd_init: getattr of %s failed", *fnp); 507 goto error; 508 } 509 nca_fio_offset(&fio) = (off64_t)attr.va_size; 510 511 goto finish; 512 513 fresh_start: 514 /* 515 * Here if no previous logging environment found or if the previous 516 * logging environment isn't usable or isn't consistent with the new 517 * fnv[]. Remove the existing symlink (if any) then create the new 518 * symlink to point to the first logfile. 519 */ 520 nca_fio_ix(&fio) = 0; 521 attr.va_mask = AT_MODE | AT_TYPE; 522 attr.va_mode = 0777; 523 attr.va_type = VLNK; 524 (void) VOP_REMOVE(dvp, symlink, kcred); 525 ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred); 526 if (ret) { 527 cmn_err(CE_WARN, "nl7c_logd_init: symlink of %s to %s failed", 528 symlink_path, nca_fio_name(&fio)); 529 goto error; 530 } 531 ret = vn_open(nca_fio_name(&fio), UIO_SYSSPACE, 532 FCREAT|FWRITE|FTRUNC, 0600, &nca_fio_vp(&fio), 0, 0); 533 if (ret) { 534 cmn_err(CE_WARN, "nl7c_logd_init: vn_open of " 535 "%s failed (error %d)", nca_fio_name(&fio), ret); 536 goto error; 537 } 538 539 /* Turn on directio */ 540 (void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO, 541 DIRECTIO_ON, 0, kcred, NULL); 542 543 finish: 544 log_buf_kmc = kmem_cache_create("NL7C_log_buf_kmc", sizeof (log_buf_t), 545 0, NULL, NULL, NULL, NULL, NULL, 0); 546 547 mutex_init(&log_lock, NULL, MUTEX_DEFAULT, NULL); 548 mutex_enter(&log_lock); 549 550 if (nl7c_logbuf_max == 0) 551 nl7c_logbuf_max = max_ncpus; 552 logv = kmem_alloc(nl7c_logbuf_max * sizeof (*logv), KM_SLEEP); 553 for (logvcnt = 0; logvcnt < nl7c_logbuf_max; logvcnt++) { 554 logv[logvcnt] = kmem_cache_alloc(log_buf_kmc, KM_SLEEP); 555 } 556 557 log_buf_alloc(KM_SLEEP); 558 559 mutex_init(&logd.lock, NULL, MUTEX_DEFAULT, NULL); 560 cv_init(&logd.wait, NULL, CV_DEFAULT, NULL); 561 logd.head = NULL; 562 logd.tail = NULL; 563 logd.worker = thread_create(NULL, 0, logd_worker, &logd, 564 0, &p0, TS_RUN, maxclsyspri); 565 566 mutex_exit(&log_lock); 567 568 /* Last, start logger timeout flush */ 569 logit_flush(NULL); 570 571 return (B_TRUE); 572 573 /* 574 * Error of some sort, free any resources in reverse order. 575 */ 576 error: 577 nca_fio_ix(&fio) = 0; 578 while (nca_fio_ix(&fio) < nca_fio_cnt(&fio)) { 579 char *name = nca_fio_name(&fio); 580 581 if ((vp = nca_fio_vp(&fio)) != NULL) 582 VN_RELE(vp); 583 kmem_free(name, strlen(name)); 584 nca_fio_ix(&fio)++; 585 } 586 nca_fio_cnt(&fio) = 0; 587 588 if (svp) 589 VN_RELE(svp); 590 591 if (dvp) 592 VN_RELE(dvp); 593 594 mutex_exit(&logd.lock); 595 return (B_FALSE); 596 } 597 598 /*ARGSUSED*/ 599 static void 600 logit_flush(void *arg) 601 { 602 static log_buf_t *lastlbp = NULL; 603 static int lastpos; 604 log_buf_t *lbp = log; 605 606 flush_tid = 0; 607 608 mutex_enter(&log_lock); 609 if (log == NULL) { 610 /* No global logbuf ? Nothing to flush. */ 611 goto out; 612 } 613 if (lbp != NULL && lbp->cur_pos > (sizeof (nca_log_buf_hdr_t)) && 614 lastlbp == lbp && lastpos == lbp->cur_pos) { 615 /* 616 * We have a logbuf and it has log data and it's the 617 * same logbuf and pos as last time and after lock 618 * still true, so flush. 619 */ 620 nca_log_stat_t *sp; 621 622 sp = &(((nca_log_buf_hdr_t *)lbp)->nca_logstats); 623 sp->n_log_size = lbp->cur_pos; 624 625 /* Link new logbuf onto end of logd and wake logd up */ 626 mutex_enter(&logd.lock); 627 log->next = NULL; 628 if (logd.tail == NULL) 629 logd.head = log; 630 else 631 logd.tail->next = log; 632 logd.tail = log; 633 cv_signal(&logd.wait); 634 635 mutex_exit(&logd.lock); 636 637 log_buf_alloc(KM_NOSLEEP); 638 } 639 640 if ((lastlbp = lbp) != NULL) 641 lastpos = lbp->cur_pos; 642 643 mutex_exit(&log_lock); 644 out: 645 /* Check again in 1 second */ 646 flush_tid = timeout(&logit_flush, NULL, hz); 647 } 648 649 void 650 nl7c_logd_log(uri_desc_t *quri, uri_desc_t *suri, time_t rtime, ipaddr_t faddr) 651 { 652 nca_request_log_t *req; 653 char *wp; 654 char *pep; 655 int sz; 656 uint32_t off = 0; 657 int kmflag = servicing_interrupt() ? KM_NOSLEEP : KM_SLEEP; 658 659 if (! nl7c_logd_enabled) 660 return; 661 662 if (! nl7c_logd_started) { 663 /* Startup logging */ 664 nl7clogd_startup(); 665 } 666 mutex_enter(&log_lock); 667 again: 668 if (log == NULL) { 669 /* No global logbuf, try to allocate one before giving up. */ 670 log_buf_alloc(kmflag); 671 if (log == NULL) { 672 /* No joy, just give up. */ 673 mutex_exit(&log_lock); 674 return; 675 } 676 } 677 /* 678 * Get a pointer to an aligned write position, a pointer to past 679 * the end of the logbuf, and a pointer to the request header. 680 * 681 * As the request header is filled in field by field addtional 682 * storage is allcated following the request header. 683 * 684 * If at any point an allocation from the logbuf overflows (i.e. 685 * resulting in a pointer > pep) the current request logging is 686 * aborted, the current logbuf is posted for write, a new logbuf 687 * is allocated, and start all over. 688 */ 689 pep = &((char *)log)[log->size]; 690 wp = (log->buffer + log->cur_pos); 691 wp = NCA_LOG_ALIGN(wp); 692 req = (nca_request_log_t *)wp; 693 if ((wp + sizeof (*req)) >= pep) goto full; 694 bzero(wp, sizeof (*req)); 695 wp += sizeof (*req); 696 697 sz = MIN((quri->path.ep - quri->path.cp), MAX_URL_LEN); 698 if ((wp + sz + 1) >= pep) goto full; 699 bcopy(quri->path.cp, wp, sz); 700 wp += sz; 701 *wp++ = 0; 702 sz++; 703 req->request_url_len = sz; 704 req->request_url = off; 705 off += sz; 706 707 /* 708 * Set response length now as the scheme log function will 709 * subtract out any header length as we want the entity body 710 * length returned for the response_len. 711 */ 712 req->response_len = (uint_t)suri->resplen; 713 714 /* Call scheme log */ 715 if (nl7c_http_log(quri, suri, req, &wp, &pep, &off)) goto full; 716 717 /* Update logbuf */ 718 log->cur_pos = (wp - log->buffer); 719 720 req->response_status = HS_OK; 721 722 req->start_process_time = (time32_t)rtime; 723 req->end_process_time = (time32_t)gethrestime_sec(); 724 725 req->remote_host = faddr; 726 727 ((nca_log_buf_hdr_t *)log)->nca_logstats.n_log_recs++; 728 mutex_exit(&log_lock); 729 return; 730 731 full: 732 /* 733 * The logbuf is full, zero fill from current 734 * write pointer through the end of the buf. 735 */ 736 wp = (log->buffer + log->cur_pos); 737 sz = pep - wp; 738 bzero(wp, sz); 739 /* 740 * Link new logbuf onto end of logd and wake logd up. 741 */ 742 mutex_enter(&logd.lock); 743 log->next = NULL; 744 if (logd.tail == NULL) 745 logd.head = log; 746 else 747 logd.tail->next = log; 748 logd.tail = log; 749 cv_signal(&logd.wait); 750 mutex_exit(&logd.lock); 751 /* 752 * Try to allocate a new global logbuf. 753 */ 754 log_buf_alloc(kmflag); 755 756 goto again; 757 } 758