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