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 deprecated 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
log_buf_alloc(int kmflag)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
logd_off()205 logd_off()
206 {
207 ;
208 }
209
210 static void
logd_log_write(kmutex_t * lock,log_buf_t * lbp)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, NULL);
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, 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, NULL, 0);
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, NULL, 0);
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
logd_worker(logd_t * logdp)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
nl7c_logd_init(int fsz,caddr_t * fnv)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, NULL);
473 if (ret) {
474 (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
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, NULL);
502 attr.va_mask = AT_SIZE;
503 ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, NULL, NULL);
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, NULL, 0);
524 ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred, NULL,
525 0);
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, 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) + 1));
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 return (B_FALSE);
595 }
596
597 /*ARGSUSED*/
598 static void
logit_flush(void * arg)599 logit_flush(void *arg)
600 {
601 static log_buf_t *lastlbp = NULL;
602 static int lastpos;
603 log_buf_t *lbp = log;
604
605 flush_tid = 0;
606
607 mutex_enter(&log_lock);
608 if (log == NULL) {
609 /* No global logbuf ? Nothing to flush. */
610 goto out;
611 }
612 if (lbp != NULL && lbp->cur_pos > (sizeof (nca_log_buf_hdr_t)) &&
613 lastlbp == lbp && lastpos == lbp->cur_pos) {
614 /*
615 * We have a logbuf and it has log data and it's the
616 * same logbuf and pos as last time and after lock
617 * still true, so flush.
618 */
619 nca_log_stat_t *sp;
620
621 sp = &(((nca_log_buf_hdr_t *)lbp)->nca_logstats);
622 sp->n_log_size = lbp->cur_pos;
623
624 /* Link new logbuf onto end of logd and wake logd up */
625 mutex_enter(&logd.lock);
626 log->next = NULL;
627 if (logd.tail == NULL)
628 logd.head = log;
629 else
630 logd.tail->next = log;
631 logd.tail = log;
632 cv_signal(&logd.wait);
633
634 mutex_exit(&logd.lock);
635
636 log_buf_alloc(KM_NOSLEEP);
637 }
638
639 if ((lastlbp = lbp) != NULL)
640 lastpos = lbp->cur_pos;
641
642 mutex_exit(&log_lock);
643 out:
644 /* Check again in 1 second */
645 flush_tid = timeout(&logit_flush, NULL, hz);
646 }
647
648 void
nl7c_logd_log(uri_desc_t * quri,uri_desc_t * suri,time_t rtime,ipaddr_t faddr)649 nl7c_logd_log(uri_desc_t *quri, uri_desc_t *suri, time_t rtime, ipaddr_t faddr)
650 {
651 nca_request_log_t *req;
652 char *wp;
653 char *pep;
654 int sz;
655 uint32_t off = 0;
656 int kmflag = servicing_interrupt() ? KM_NOSLEEP : KM_SLEEP;
657
658 if (! nl7c_logd_enabled)
659 return;
660
661 if (! nl7c_logd_started) {
662 /* Startup logging */
663 nl7clogd_startup();
664 }
665 mutex_enter(&log_lock);
666 again:
667 if (log == NULL) {
668 /* No global logbuf, try to allocate one before giving up. */
669 log_buf_alloc(kmflag);
670 if (log == NULL) {
671 /* No joy, just give up. */
672 mutex_exit(&log_lock);
673 return;
674 }
675 }
676 /*
677 * Get a pointer to an aligned write position, a pointer to past
678 * the end of the logbuf, and a pointer to the request header.
679 *
680 * As the request header is filled in field by field addtional
681 * storage is allcated following the request header.
682 *
683 * If at any point an allocation from the logbuf overflows (i.e.
684 * resulting in a pointer > pep) the current request logging is
685 * aborted, the current logbuf is posted for write, a new logbuf
686 * is allocated, and start all over.
687 */
688 pep = &((char *)log)[log->size];
689 wp = (log->buffer + log->cur_pos);
690 wp = NCA_LOG_ALIGN(wp);
691 req = (nca_request_log_t *)wp;
692 if ((wp + sizeof (*req)) >= pep) goto full;
693 bzero(wp, sizeof (*req));
694 wp += sizeof (*req);
695
696 sz = MIN((quri->path.ep - quri->path.cp), MAX_URL_LEN);
697 if ((wp + sz + 1) >= pep) goto full;
698 bcopy(quri->path.cp, wp, sz);
699 wp += sz;
700 *wp++ = 0;
701 sz++;
702 req->request_url_len = sz;
703 req->request_url = off;
704 off += sz;
705
706 /*
707 * Set response length now as the scheme log function will
708 * subtract out any header length as we want the entity body
709 * length returned for the response_len.
710 */
711 req->response_len = (uint_t)suri->resplen;
712
713 /* Call scheme log */
714 if (nl7c_http_log(quri, suri, req, &wp, &pep, &off)) goto full;
715
716 /* Update logbuf */
717 log->cur_pos = (wp - log->buffer);
718
719 req->response_status = HS_OK;
720
721 req->start_process_time = (time32_t)rtime;
722 req->end_process_time = (time32_t)gethrestime_sec();
723
724 req->remote_host = faddr;
725
726 ((nca_log_buf_hdr_t *)log)->nca_logstats.n_log_recs++;
727 mutex_exit(&log_lock);
728 return;
729
730 full:
731 /*
732 * The logbuf is full, zero fill from current
733 * write pointer through the end of the buf.
734 */
735 wp = (log->buffer + log->cur_pos);
736 sz = pep - wp;
737 bzero(wp, sz);
738 /*
739 * Link new logbuf onto end of logd and wake logd up.
740 */
741 mutex_enter(&logd.lock);
742 log->next = NULL;
743 if (logd.tail == NULL)
744 logd.head = log;
745 else
746 logd.tail->next = log;
747 logd.tail = log;
748 cv_signal(&logd.wait);
749 mutex_exit(&logd.lock);
750 /*
751 * Try to allocate a new global logbuf.
752 */
753 log_buf_alloc(kmflag);
754
755 goto again;
756 }
757