10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
54155Sfr80241 * Common Development and Distribution License (the "License").
64155Sfr80241 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
224155Sfr80241 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/sysmacros.h>
290Sstevel@tonic-gate #include <sys/callb.h>
300Sstevel@tonic-gate #include <sys/fcntl.h>
310Sstevel@tonic-gate #include <sys/filio.h>
320Sstevel@tonic-gate #include <sys/pathname.h>
330Sstevel@tonic-gate #include <sys/cpuvar.h>
340Sstevel@tonic-gate #include <sys/promif.h>
350Sstevel@tonic-gate #include <fs/sockfs/nl7c.h>
360Sstevel@tonic-gate #include <fs/sockfs/nl7curi.h>
370Sstevel@tonic-gate
380Sstevel@tonic-gate #include <inet/nca/ncadoorhdr.h>
390Sstevel@tonic-gate #include <inet/nca/ncalogd.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate extern boolean_t nl7c_logd_enabled;
420Sstevel@tonic-gate extern boolean_t nl7c_logd_started;
430Sstevel@tonic-gate extern boolean_t nl7c_logd_cycle;
440Sstevel@tonic-gate
450Sstevel@tonic-gate extern void nl7clogd_startup(void);
460Sstevel@tonic-gate
470Sstevel@tonic-gate extern boolean_t nl7c_http_log(uri_desc_t *, uri_desc_t *,
480Sstevel@tonic-gate nca_request_log_t *, char **, char **, uint32_t *);
490Sstevel@tonic-gate
500Sstevel@tonic-gate static void logit_flush(void *);
510Sstevel@tonic-gate
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate * NL7C reuses the NCA logging scheme, the directory "/var/nca" contains
540Sstevel@tonic-gate * the symlink "current" to 1 of up to 16 NCA BLF logging files, by default
550Sstevel@tonic-gate * a single logging file "log", optionally paths of up to 16 log files can
560Sstevel@tonic-gate * be specified via ncalogd.conf(4), note that these log files need not be
570Sstevel@tonic-gate * in the "/var/nca" directory.
580Sstevel@tonic-gate *
590Sstevel@tonic-gate * NL7C reuses the NCA logging APIs defined in <inet/nca/ncalogd.h>, at
60*5331Samw * some future date (when NCA is deprecated or improvements are needed)
610Sstevel@tonic-gate * these need to be moved into NL7C.
620Sstevel@tonic-gate *
630Sstevel@tonic-gate * NL7C implements logging differently in 2 ways, 1st the initialization
640Sstevel@tonic-gate * is handled completely in the kernel by NL7C when it's enabled vs NCA
650Sstevel@tonic-gate * when the kmod was loaded, 2nd a simple worker thread with a FIFO queue
660Sstevel@tonic-gate * is used to process log_buf_t's instead of a squeue_t (this is done as
670Sstevel@tonic-gate * squeue_t's are private to NCA and IP at some future date we may us an
680Sstevel@tonic-gate * IP squeue_t):
690Sstevel@tonic-gate *
700Sstevel@tonic-gate * logd_t - used by various functions to manage a singly linked
710Sstevel@tonic-gate * grounded list of log_buf_t's and it's worker thread.
720Sstevel@tonic-gate */
730Sstevel@tonic-gate
740Sstevel@tonic-gate typedef struct logd_s {
750Sstevel@tonic-gate log_buf_t *head;
760Sstevel@tonic-gate log_buf_t *tail;
770Sstevel@tonic-gate kthread_t *worker;
780Sstevel@tonic-gate kcondvar_t wait;
790Sstevel@tonic-gate kmutex_t lock;
800Sstevel@tonic-gate } logd_t;
810Sstevel@tonic-gate
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate * In-kernel logging:
840Sstevel@tonic-gate *
850Sstevel@tonic-gate * nl7c_logbuf_max - tunable for the number of preallocated next
860Sstevel@tonic-gate * log_buf_t(s) for use by log_buf_alloc(), note if the value is
870Sstevel@tonic-gate * 0 (the default) then max_cpus worth will be allocated.
880Sstevel@tonic-gate *
890Sstevel@tonic-gate * logd - global logd_t used to post log_buf_t's too.
900Sstevel@tonic-gate *
910Sstevel@tonic-gate * log - global current log_buf_t that logit() logs too.
920Sstevel@tonic-gate *
930Sstevel@tonic-gate * logv[] - vector of available next logbuf(s) such that when
940Sstevel@tonic-gate * logbuf is filled another can be used while being processed by
950Sstevel@tonic-gate * the logger() and kmem_cache_alloc() of a replacement is done.
960Sstevel@tonic-gate *
970Sstevel@tonic-gate * logvcnt - count of logv[] vector element(s) and the index
980Sstevel@tonic-gate * plus 1 of the next logbuf.
990Sstevel@tonic-gate *
1000Sstevel@tonic-gate * log_buf_kmc - the kmem_cache to alloc/free log_buf_t's from/to.
1010Sstevel@tonic-gate *
1020Sstevel@tonic-gate * fio - the global nca_fio_t used to manage file i/o to a logfile.
1030Sstevel@tonic-gate *
1040Sstevel@tonic-gate * dir - path to the directory where the current logfile symlink
1050Sstevel@tonic-gate * is created and the default directory for logfile(s).
1060Sstevel@tonic-gate *
1070Sstevel@tonic-gate * symlink - name of the logfile symlink.
1080Sstevel@tonic-gate *
1090Sstevel@tonic-gate * symlink_path - path to the logfile symlink.
1100Sstevel@tonic-gate *
1110Sstevel@tonic-gate * log_lock - the kmutex_t used to guarantee atomic access of
1120Sstevel@tonic-gate * all of the above.
1130Sstevel@tonic-gate *
1140Sstevel@tonic-gate * flush_tid - logit_flush() timeout id.
1150Sstevel@tonic-gate *
1160Sstevel@tonic-gate * LOGBUFV_ALLOC() - macro used to add log_buf_t(s) to logv[].
1170Sstevel@tonic-gate */
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate int nl7c_logbuf_max = 0;
1200Sstevel@tonic-gate static logd_t logd;
1210Sstevel@tonic-gate static log_buf_t *log = NULL;
1220Sstevel@tonic-gate static log_buf_t **logv = NULL;
1230Sstevel@tonic-gate static int logvcnt = 0;
1240Sstevel@tonic-gate static kmem_cache_t *log_buf_kmc;
1250Sstevel@tonic-gate static nca_fio_t fio;
1260Sstevel@tonic-gate static caddr_t dir = "/var/nca/";
1270Sstevel@tonic-gate static caddr_t symlink = "current";
1280Sstevel@tonic-gate static caddr_t symlink_dir = "/var/nca";
1290Sstevel@tonic-gate static caddr_t symlink_path = "/var/nca/current";
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate static kmutex_t log_lock;
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate static timeout_id_t flush_tid;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate #define LOGBUFV_ALLOC(kmflag) { \
1360Sstevel@tonic-gate log_buf_t *_p; \
1370Sstevel@tonic-gate \
1380Sstevel@tonic-gate ASSERT(mutex_owned(&log_lock)); \
1390Sstevel@tonic-gate while (logvcnt < nl7c_logbuf_max) { \
1400Sstevel@tonic-gate /*CONSTCOND*/ \
1410Sstevel@tonic-gate if (kmflag == KM_SLEEP) \
1420Sstevel@tonic-gate mutex_exit(&log_lock); \
1430Sstevel@tonic-gate _p = kmem_cache_alloc(log_buf_kmc, kmflag); \
1440Sstevel@tonic-gate /*CONSTCOND*/ \
1450Sstevel@tonic-gate if (kmflag == KM_SLEEP) { \
1460Sstevel@tonic-gate mutex_enter(&log_lock); \
1470Sstevel@tonic-gate if (logvcnt == nl7c_logbuf_max) { \
1480Sstevel@tonic-gate mutex_exit(&log_lock); \
1490Sstevel@tonic-gate kmem_cache_free(log_buf_kmc, _p); \
1500Sstevel@tonic-gate mutex_enter(&log_lock); \
1510Sstevel@tonic-gate break; \
1520Sstevel@tonic-gate } \
1530Sstevel@tonic-gate } else { \
1540Sstevel@tonic-gate if (_p == NULL) { \
1550Sstevel@tonic-gate break; \
1560Sstevel@tonic-gate } \
1570Sstevel@tonic-gate } \
1580Sstevel@tonic-gate logv[logvcnt++] = _p; \
1590Sstevel@tonic-gate } \
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate * Exports for inet/nca/ncaddi.c:
1640Sstevel@tonic-gate */
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate nca_fio_t *nl7c_logd_fio = &fio;
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate static void
log_buf_alloc(int kmflag)1690Sstevel@tonic-gate log_buf_alloc(int kmflag)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate nca_log_buf_hdr_t *hdr;
1720Sstevel@tonic-gate static ulong_t seq = 0;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate ASSERT(mutex_owned(&log_lock));
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate if (logvcnt == 0) {
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate * No logv[] to use for the new log global logbuf,
1790Sstevel@tonic-gate * try to allocate one or more before giving up.
1800Sstevel@tonic-gate */
1810Sstevel@tonic-gate LOGBUFV_ALLOC(kmflag);
1820Sstevel@tonic-gate if (logvcnt == 0) {
1830Sstevel@tonic-gate /* No joy, just give up. */
1840Sstevel@tonic-gate log = NULL;
1850Sstevel@tonic-gate return;
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate log = logv[--logvcnt];
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate log->size = NCA_DEFAULT_LOG_BUF_SIZE;
1910Sstevel@tonic-gate log->cur_pos = sizeof (*hdr);
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate hdr = (nca_log_buf_hdr_t *)&log->buffer;
1940Sstevel@tonic-gate hdr->nca_loghdr.nca_version = NCA_LOG_VERSION1;
1950Sstevel@tonic-gate hdr->nca_loghdr.nca_op = log_op;
1960Sstevel@tonic-gate hdr->nca_logstats.n_log_size = NCA_DEFAULT_LOG_BUF_SIZE - sizeof (*hdr);
1970Sstevel@tonic-gate hdr->nca_logstats.n_log_recs = 0;
1980Sstevel@tonic-gate hdr->nca_logstats.n_log_upcall = seq++;
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate /* Try to allocate for at least the one we just used */
2010Sstevel@tonic-gate LOGBUFV_ALLOC(kmflag);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate static void
logd_off()2050Sstevel@tonic-gate logd_off()
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate ;
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate static void
logd_log_write(kmutex_t * lock,log_buf_t * lbp)2110Sstevel@tonic-gate logd_log_write(kmutex_t *lock, log_buf_t *lbp)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate nca_log_buf_hdr_t *hdr = (nca_log_buf_hdr_t *)lbp->buffer;
2140Sstevel@tonic-gate nca_log_stat_t *sts = &hdr->nca_logstats;
2150Sstevel@tonic-gate int size = sts->n_log_size + sizeof (*hdr);
2160Sstevel@tonic-gate vnode_t *vp;
2170Sstevel@tonic-gate uio_t uio;
2180Sstevel@tonic-gate iovec_t iov;
2190Sstevel@tonic-gate int ret;
2200Sstevel@tonic-gate boolean_t noretry = B_FALSE;
2210Sstevel@tonic-gate vattr_t attr;
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate if (size & (DEV_BSIZE - 1)) {
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate * Not appropriately sized for directio(),
2260Sstevel@tonic-gate * add some filler so it is.
2270Sstevel@tonic-gate */
2280Sstevel@tonic-gate sts->n_log_size += DEV_BSIZE - (size & (DEV_BSIZE - 1));
2290Sstevel@tonic-gate size = sts->n_log_size + sizeof (*hdr);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate retry:
2320Sstevel@tonic-gate if (nca_fio_offset(&fio) + size <= nca_fio_size(&fio)) {
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate * Room in the current log file so write the logbuf out,
2350Sstevel@tonic-gate * exit the logd lock while doing the i/o as to not block
2360Sstevel@tonic-gate * queuing.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate mutex_exit(lock);
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate vp = nca_fio_vp(&fio);
2410Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
2420Sstevel@tonic-gate iov.iov_base = lbp->buffer;
2430Sstevel@tonic-gate iov.iov_len = size;
2440Sstevel@tonic-gate uio.uio_iov = &iov;
2450Sstevel@tonic-gate uio.uio_iovcnt = 1;
2460Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
2470Sstevel@tonic-gate uio.uio_fmode = 0;
2480Sstevel@tonic-gate uio.uio_loffset = (u_offset_t)nca_fio_offset(&fio);
2490Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl;
2500Sstevel@tonic-gate uio.uio_resid = size;
2510Sstevel@tonic-gate ret = VOP_WRITE(vp, &uio, 0, kcred, NULL);
2520Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
2530Sstevel@tonic-gate if (ret != 0) {
2540Sstevel@tonic-gate if (ret == EFBIG) {
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate * Out of space for this file,
2570Sstevel@tonic-gate * retry with the next.
2580Sstevel@tonic-gate */
2590Sstevel@tonic-gate nca_fio_size(&fio) = nca_fio_offset(&fio);
2600Sstevel@tonic-gate if (noretry) {
2610Sstevel@tonic-gate nl7c_logd_enabled = B_FALSE;
2620Sstevel@tonic-gate goto done;
2630Sstevel@tonic-gate } else
2640Sstevel@tonic-gate goto next;
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate nca_fio_offset(&fio) = uio.uio_loffset;
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate mutex_enter(lock);
2700Sstevel@tonic-gate goto done;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate * Current logfile doesn't have sufficient space
2750Sstevel@tonic-gate * so move on to next file (if any).
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate next:
2780Sstevel@tonic-gate mutex_exit(lock);
2790Sstevel@tonic-gate /* Close current file */
2800Sstevel@tonic-gate ret = VOP_CLOSE(nca_fio_vp(&fio), FCREAT|FWRITE|FAPPEND|FTRUNC,
281*5331Samw 1, (offset_t)0, kcred, NULL);
2820Sstevel@tonic-gate nca_fio_vp(&fio) = NULL;
2830Sstevel@tonic-gate if (ret) {
2840Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd: close of %s failed (error %d)",
2850Sstevel@tonic-gate nca_fio_name(&fio), ret);
2860Sstevel@tonic-gate nl7c_logd_enabled = B_FALSE;
2870Sstevel@tonic-gate logd_off();
2880Sstevel@tonic-gate return;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /* Go to next file */
2920Sstevel@tonic-gate nca_fio_ix(&fio)++;
2930Sstevel@tonic-gate if (nca_fio_ix(&fio) == nca_fio_cnt(&fio)) {
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate * We have reached the last file. If cycling
2960Sstevel@tonic-gate * is not on, disable logging and bailout.
2970Sstevel@tonic-gate */
2980Sstevel@tonic-gate if (nl7c_logd_cycle) {
2990Sstevel@tonic-gate /* Start from the first file */
3000Sstevel@tonic-gate nca_fio_ix(&fio) = 0;
3010Sstevel@tonic-gate } else {
3020Sstevel@tonic-gate nca_fio_ix(&fio)--;
3030Sstevel@tonic-gate nl7c_logd_enabled = B_FALSE;
3040Sstevel@tonic-gate logd_off();
3050Sstevel@tonic-gate return;
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate /* Open the next log file */
3100Sstevel@tonic-gate ret = vn_open(nca_fio_name(&fio), UIO_SYSSPACE, FCREAT|FWRITE|FTRUNC,
3110Sstevel@tonic-gate 0600, &nca_fio_vp(&fio), 0, 0);
3120Sstevel@tonic-gate if (ret) {
3130Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd: vn_open of %s failed (error %d)",
3140Sstevel@tonic-gate nca_fio_name(&fio), ret);
3150Sstevel@tonic-gate nl7c_logd_enabled = B_FALSE;
3160Sstevel@tonic-gate logd_off();
3170Sstevel@tonic-gate return;
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate /* Turn on directio */
3210Sstevel@tonic-gate (void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO,
322*5331Samw DIRECTIO_ON, 0, kcred, NULL, NULL);
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate /* Start writing from the begining of the file */
3250Sstevel@tonic-gate nca_fio_offset(&fio) = 0;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate /* Remove the current symlink */
328*5331Samw (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred, NULL, 0);
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate attr.va_mask = AT_MODE | AT_TYPE;
3310Sstevel@tonic-gate attr.va_mode = 0777;
3320Sstevel@tonic-gate attr.va_type = VLNK;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /* Create symlink to the new log file */
3350Sstevel@tonic-gate ret = VOP_SYMLINK(nca_fio_dvp(&fio), symlink,
336*5331Samw &attr, nca_fio_name(&fio), kcred, NULL, 0);
3370Sstevel@tonic-gate if (ret) {
3380Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd: symlink of %s to %s failed",
3390Sstevel@tonic-gate symlink, nca_fio_name(&fio));
3400Sstevel@tonic-gate nl7c_logd_enabled = B_FALSE;
3410Sstevel@tonic-gate logd_off();
3420Sstevel@tonic-gate return;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate mutex_enter(lock);
3450Sstevel@tonic-gate goto retry;
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate done:
3480Sstevel@tonic-gate if (logvcnt < nl7c_logbuf_max) {
3490Sstevel@tonic-gate /* May need to allocate some logbuf(s) for logv[] */
3500Sstevel@tonic-gate mutex_enter(&log_lock);
3510Sstevel@tonic-gate if (logvcnt < nl7c_logbuf_max) {
3520Sstevel@tonic-gate /*
3530Sstevel@tonic-gate * After acquiring the lock still need logbuf(s),
3540Sstevel@tonic-gate * if the global logbuf pointer is NULL then call
3550Sstevel@tonic-gate * log_buf_alloc() as it will fill up logbugv[]
3560Sstevel@tonic-gate * and initialize a new logbuf else fill up just
3570Sstevel@tonic-gate * the logv[] here.
3580Sstevel@tonic-gate */
3590Sstevel@tonic-gate if (log == NULL) {
3600Sstevel@tonic-gate log_buf_alloc(KM_SLEEP);
3610Sstevel@tonic-gate } else {
3620Sstevel@tonic-gate /*LINTED*/
3630Sstevel@tonic-gate LOGBUFV_ALLOC(KM_SLEEP);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate mutex_exit(&log_lock);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate static void
logd_worker(logd_t * logdp)3710Sstevel@tonic-gate logd_worker(logd_t *logdp)
3720Sstevel@tonic-gate {
3730Sstevel@tonic-gate log_buf_t *lbp;
3740Sstevel@tonic-gate kmutex_t *lock = &logdp->lock;
3750Sstevel@tonic-gate kcondvar_t *wait = &logdp->wait;
3760Sstevel@tonic-gate callb_cpr_t cprinfo;
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, lock, callb_generic_cpr, "nl7c");
3790Sstevel@tonic-gate mutex_enter(lock);
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate for (;;) {
3820Sstevel@tonic-gate /* Wait for something to do */
3830Sstevel@tonic-gate while ((lbp = logdp->head) == NULL) {
3840Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo);
3850Sstevel@tonic-gate cv_wait(wait, lock);
3860Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, lock);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate if ((logdp->head = lbp->next) == NULL)
3890Sstevel@tonic-gate logdp->tail = NULL;
3900Sstevel@tonic-gate /* Got a logbuf to write out */
3910Sstevel@tonic-gate if (nl7c_logd_enabled)
3920Sstevel@tonic-gate logd_log_write(lock, lbp);
3930Sstevel@tonic-gate kmem_cache_free(log_buf_kmc, lbp);
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate boolean_t
nl7c_logd_init(int fsz,caddr_t * fnv)3980Sstevel@tonic-gate nl7c_logd_init(int fsz, caddr_t *fnv)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate vnode_t *dvp;
4010Sstevel@tonic-gate vnode_t *svp;
4020Sstevel@tonic-gate vnode_t *vp;
4030Sstevel@tonic-gate int ret;
4040Sstevel@tonic-gate caddr_t *fnp;
4050Sstevel@tonic-gate vattr_t attr;
4060Sstevel@tonic-gate uio_t uio;
4070Sstevel@tonic-gate iovec_t iov;
4080Sstevel@tonic-gate char fbuf[TYPICALMAXPATHLEN + 1];
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate /*
4110Sstevel@tonic-gate * Initialize the global logfio.
4120Sstevel@tonic-gate */
4130Sstevel@tonic-gate nca_fio_cnt(&fio) = 0;
4140Sstevel@tonic-gate nca_fio_ix(&fio) = 0;
4150Sstevel@tonic-gate fnp = fnv;
4160Sstevel@tonic-gate while (*fnp != NULL) {
4170Sstevel@tonic-gate nca_fio_cnt(&fio)++;
4180Sstevel@tonic-gate nca_fio_name(&fio) = *fnp;
4190Sstevel@tonic-gate nca_fio_size(&fio) = fsz;
4200Sstevel@tonic-gate nca_fio_offset(&fio) = 0;
4210Sstevel@tonic-gate nca_fio_file(&fio) = nca_fio_ix(&fio);
4220Sstevel@tonic-gate nca_fio_vp(&fio) = NULL;
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate if (++fnp == &fnv[NCA_FIOV_SZ])
4250Sstevel@tonic-gate break;
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate nca_fio_ix(&fio)++;
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate /*
4300Sstevel@tonic-gate * See if we can start logging from where we left off last time,
4310Sstevel@tonic-gate * first check if the symlink exists.
4320Sstevel@tonic-gate */
4330Sstevel@tonic-gate dvp = NULL;
4340Sstevel@tonic-gate ret = lookupname(symlink_path, UIO_SYSSPACE, NO_FOLLOW, &dvp, &svp);
4350Sstevel@tonic-gate if (ret || dvp == NULL || svp == NULL) {
4360Sstevel@tonic-gate if (dvp == NULL) {
4370Sstevel@tonic-gate /* No NCA symlink directory, create one */
4380Sstevel@tonic-gate attr.va_mask = AT_MODE | AT_TYPE;
4390Sstevel@tonic-gate attr.va_mode = 0755;
4400Sstevel@tonic-gate attr.va_type = VDIR;
4410Sstevel@tonic-gate ret = vn_create(symlink_dir, UIO_SYSSPACE, &attr,
4420Sstevel@tonic-gate EXCL, 0, &dvp, CRMKDIR, 0, 0);
4430Sstevel@tonic-gate if (ret) {
4440Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: create"
4450Sstevel@tonic-gate " symlink dir of %s failed(%d).",
4460Sstevel@tonic-gate symlink_dir, ret);
4470Sstevel@tonic-gate goto error;
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate }
4504155Sfr80241 nca_fio_dvp(&fio) = dvp;
4510Sstevel@tonic-gate /* No symlink so don't know were to start from */
4520Sstevel@tonic-gate goto fresh_start;
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate /* Save the symlink dir vnode */
4550Sstevel@tonic-gate nca_fio_dvp(&fio) = dvp;
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate /* Check if the file pointed by the symlink exists */
4580Sstevel@tonic-gate ret = lookupname(symlink_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
4590Sstevel@tonic-gate if (ret || vp == NULL)
4600Sstevel@tonic-gate goto fresh_start;
4610Sstevel@tonic-gate VN_RELE(vp);
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /* Read the symlink and find it in fnv[], else fresh start */
4640Sstevel@tonic-gate iov.iov_len = TYPICALMAXPATHLEN;
4650Sstevel@tonic-gate iov.iov_base = fbuf;
4660Sstevel@tonic-gate uio.uio_iov = &iov;
4670Sstevel@tonic-gate uio.uio_iovcnt = 1;
4680Sstevel@tonic-gate uio.uio_resid = iov.iov_len;
4690Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
4700Sstevel@tonic-gate uio.uio_loffset = 0;
4710Sstevel@tonic-gate uio.uio_fmode = 0;
472*5331Samw ret = VOP_READLINK(svp, &uio, kcred, NULL);
4730Sstevel@tonic-gate if (ret) {
474*5331Samw (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
4750Sstevel@tonic-gate goto fresh_start;
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate /* Null terminate the buf */
4790Sstevel@tonic-gate fbuf[TYPICALMAXPATHLEN - (int)uio.uio_resid] = '\0';
4800Sstevel@tonic-gate fnp = fnv;
4810Sstevel@tonic-gate nca_fio_ix(&fio) = 0;
4820Sstevel@tonic-gate while (*fnp != NULL) {
4830Sstevel@tonic-gate if (strcmp(*fnp, fbuf) == 0)
4840Sstevel@tonic-gate break;
4850Sstevel@tonic-gate if (++fnp == &fnv[NCA_FIOV_SZ])
4860Sstevel@tonic-gate goto fresh_start;
4870Sstevel@tonic-gate nca_fio_ix(&fio)++;
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate if (*fnp == NULL)
4900Sstevel@tonic-gate goto fresh_start;
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate /* Start writing to the end of the file */
4930Sstevel@tonic-gate ret = vn_open(*fnp, UIO_SYSSPACE,
4940Sstevel@tonic-gate FCREAT|FWRITE|FAPPEND, 0600, &vp, 0, 0);
4950Sstevel@tonic-gate if (ret) {
4960Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: vn_open of "
4970Sstevel@tonic-gate "%s failed (error %d)", *fnp, ret);
4980Sstevel@tonic-gate goto error;
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate nca_fio_vp(&fio) = vp;
501*5331Samw (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL, NULL);
5020Sstevel@tonic-gate attr.va_mask = AT_SIZE;
503*5331Samw ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, NULL, NULL);
5040Sstevel@tonic-gate if (ret) {
5050Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: getattr of %s failed", *fnp);
5060Sstevel@tonic-gate goto error;
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate nca_fio_offset(&fio) = (off64_t)attr.va_size;
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate goto finish;
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate fresh_start:
5130Sstevel@tonic-gate /*
5140Sstevel@tonic-gate * Here if no previous logging environment found or if the previous
5150Sstevel@tonic-gate * logging environment isn't usable or isn't consistent with the new
5160Sstevel@tonic-gate * fnv[]. Remove the existing symlink (if any) then create the new
5170Sstevel@tonic-gate * symlink to point to the first logfile.
5180Sstevel@tonic-gate */
5190Sstevel@tonic-gate nca_fio_ix(&fio) = 0;
5200Sstevel@tonic-gate attr.va_mask = AT_MODE | AT_TYPE;
5210Sstevel@tonic-gate attr.va_mode = 0777;
5220Sstevel@tonic-gate attr.va_type = VLNK;
523*5331Samw (void) VOP_REMOVE(dvp, symlink, kcred, NULL, 0);
524*5331Samw ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred, NULL,
525*5331Samw 0);
5260Sstevel@tonic-gate if (ret) {
5270Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: symlink of %s to %s failed",
5280Sstevel@tonic-gate symlink_path, nca_fio_name(&fio));
5290Sstevel@tonic-gate goto error;
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate ret = vn_open(nca_fio_name(&fio), UIO_SYSSPACE,
5320Sstevel@tonic-gate FCREAT|FWRITE|FTRUNC, 0600, &nca_fio_vp(&fio), 0, 0);
5330Sstevel@tonic-gate if (ret) {
5340Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: vn_open of "
5350Sstevel@tonic-gate "%s failed (error %d)", nca_fio_name(&fio), ret);
5360Sstevel@tonic-gate goto error;
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate /* Turn on directio */
5400Sstevel@tonic-gate (void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO,
541*5331Samw DIRECTIO_ON, 0, kcred, NULL, NULL);
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate finish:
5440Sstevel@tonic-gate log_buf_kmc = kmem_cache_create("NL7C_log_buf_kmc", sizeof (log_buf_t),
5450Sstevel@tonic-gate 0, NULL, NULL, NULL, NULL, NULL, 0);
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate mutex_init(&log_lock, NULL, MUTEX_DEFAULT, NULL);
5480Sstevel@tonic-gate mutex_enter(&log_lock);
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate if (nl7c_logbuf_max == 0)
5510Sstevel@tonic-gate nl7c_logbuf_max = max_ncpus;
5520Sstevel@tonic-gate logv = kmem_alloc(nl7c_logbuf_max * sizeof (*logv), KM_SLEEP);
5530Sstevel@tonic-gate for (logvcnt = 0; logvcnt < nl7c_logbuf_max; logvcnt++) {
5540Sstevel@tonic-gate logv[logvcnt] = kmem_cache_alloc(log_buf_kmc, KM_SLEEP);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate log_buf_alloc(KM_SLEEP);
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate mutex_init(&logd.lock, NULL, MUTEX_DEFAULT, NULL);
5600Sstevel@tonic-gate cv_init(&logd.wait, NULL, CV_DEFAULT, NULL);
5610Sstevel@tonic-gate logd.head = NULL;
5620Sstevel@tonic-gate logd.tail = NULL;
5630Sstevel@tonic-gate logd.worker = thread_create(NULL, 0, logd_worker, &logd,
5640Sstevel@tonic-gate 0, &p0, TS_RUN, maxclsyspri);
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate mutex_exit(&log_lock);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate /* Last, start logger timeout flush */
5690Sstevel@tonic-gate logit_flush(NULL);
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate return (B_TRUE);
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate /*
5740Sstevel@tonic-gate * Error of some sort, free any resources in reverse order.
5750Sstevel@tonic-gate */
5760Sstevel@tonic-gate error:
5770Sstevel@tonic-gate nca_fio_ix(&fio) = 0;
5780Sstevel@tonic-gate while (nca_fio_ix(&fio) < nca_fio_cnt(&fio)) {
5790Sstevel@tonic-gate char *name = nca_fio_name(&fio);
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if ((vp = nca_fio_vp(&fio)) != NULL)
5820Sstevel@tonic-gate VN_RELE(vp);
5835145Sgeorges kmem_free(name, (strlen(name) + 1));
5840Sstevel@tonic-gate nca_fio_ix(&fio)++;
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate nca_fio_cnt(&fio) = 0;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate if (svp)
5890Sstevel@tonic-gate VN_RELE(svp);
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate if (dvp)
5920Sstevel@tonic-gate VN_RELE(dvp);
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate return (B_FALSE);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate /*ARGSUSED*/
5980Sstevel@tonic-gate static void
logit_flush(void * arg)5990Sstevel@tonic-gate logit_flush(void *arg)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate static log_buf_t *lastlbp = NULL;
6020Sstevel@tonic-gate static int lastpos;
6030Sstevel@tonic-gate log_buf_t *lbp = log;
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate flush_tid = 0;
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate mutex_enter(&log_lock);
6080Sstevel@tonic-gate if (log == NULL) {
6090Sstevel@tonic-gate /* No global logbuf ? Nothing to flush. */
6100Sstevel@tonic-gate goto out;
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate if (lbp != NULL && lbp->cur_pos > (sizeof (nca_log_buf_hdr_t)) &&
6130Sstevel@tonic-gate lastlbp == lbp && lastpos == lbp->cur_pos) {
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate * We have a logbuf and it has log data and it's the
6160Sstevel@tonic-gate * same logbuf and pos as last time and after lock
6170Sstevel@tonic-gate * still true, so flush.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate nca_log_stat_t *sp;
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate sp = &(((nca_log_buf_hdr_t *)lbp)->nca_logstats);
6220Sstevel@tonic-gate sp->n_log_size = lbp->cur_pos;
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate /* Link new logbuf onto end of logd and wake logd up */
6250Sstevel@tonic-gate mutex_enter(&logd.lock);
6260Sstevel@tonic-gate log->next = NULL;
6270Sstevel@tonic-gate if (logd.tail == NULL)
6280Sstevel@tonic-gate logd.head = log;
6290Sstevel@tonic-gate else
6300Sstevel@tonic-gate logd.tail->next = log;
6310Sstevel@tonic-gate logd.tail = log;
6320Sstevel@tonic-gate cv_signal(&logd.wait);
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate mutex_exit(&logd.lock);
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate log_buf_alloc(KM_NOSLEEP);
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate if ((lastlbp = lbp) != NULL)
6400Sstevel@tonic-gate lastpos = lbp->cur_pos;
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate mutex_exit(&log_lock);
6430Sstevel@tonic-gate out:
6440Sstevel@tonic-gate /* Check again in 1 second */
6450Sstevel@tonic-gate flush_tid = timeout(&logit_flush, NULL, hz);
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate void
nl7c_logd_log(uri_desc_t * quri,uri_desc_t * suri,time_t rtime,ipaddr_t faddr)6490Sstevel@tonic-gate nl7c_logd_log(uri_desc_t *quri, uri_desc_t *suri, time_t rtime, ipaddr_t faddr)
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate nca_request_log_t *req;
6520Sstevel@tonic-gate char *wp;
6530Sstevel@tonic-gate char *pep;
6540Sstevel@tonic-gate int sz;
6550Sstevel@tonic-gate uint32_t off = 0;
6560Sstevel@tonic-gate int kmflag = servicing_interrupt() ? KM_NOSLEEP : KM_SLEEP;
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate if (! nl7c_logd_enabled)
6590Sstevel@tonic-gate return;
6600Sstevel@tonic-gate
6610Sstevel@tonic-gate if (! nl7c_logd_started) {
6620Sstevel@tonic-gate /* Startup logging */
6630Sstevel@tonic-gate nl7clogd_startup();
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate mutex_enter(&log_lock);
6660Sstevel@tonic-gate again:
6670Sstevel@tonic-gate if (log == NULL) {
6680Sstevel@tonic-gate /* No global logbuf, try to allocate one before giving up. */
6690Sstevel@tonic-gate log_buf_alloc(kmflag);
6700Sstevel@tonic-gate if (log == NULL) {
6710Sstevel@tonic-gate /* No joy, just give up. */
6720Sstevel@tonic-gate mutex_exit(&log_lock);
6730Sstevel@tonic-gate return;
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate /*
6770Sstevel@tonic-gate * Get a pointer to an aligned write position, a pointer to past
6780Sstevel@tonic-gate * the end of the logbuf, and a pointer to the request header.
6790Sstevel@tonic-gate *
6800Sstevel@tonic-gate * As the request header is filled in field by field addtional
6810Sstevel@tonic-gate * storage is allcated following the request header.
6820Sstevel@tonic-gate *
6830Sstevel@tonic-gate * If at any point an allocation from the logbuf overflows (i.e.
6840Sstevel@tonic-gate * resulting in a pointer > pep) the current request logging is
6850Sstevel@tonic-gate * aborted, the current logbuf is posted for write, a new logbuf
6860Sstevel@tonic-gate * is allocated, and start all over.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate pep = &((char *)log)[log->size];
6890Sstevel@tonic-gate wp = (log->buffer + log->cur_pos);
6900Sstevel@tonic-gate wp = NCA_LOG_ALIGN(wp);
6910Sstevel@tonic-gate req = (nca_request_log_t *)wp;
6920Sstevel@tonic-gate if ((wp + sizeof (*req)) >= pep) goto full;
6930Sstevel@tonic-gate bzero(wp, sizeof (*req));
6940Sstevel@tonic-gate wp += sizeof (*req);
6950Sstevel@tonic-gate
6960Sstevel@tonic-gate sz = MIN((quri->path.ep - quri->path.cp), MAX_URL_LEN);
6970Sstevel@tonic-gate if ((wp + sz + 1) >= pep) goto full;
6980Sstevel@tonic-gate bcopy(quri->path.cp, wp, sz);
6990Sstevel@tonic-gate wp += sz;
7000Sstevel@tonic-gate *wp++ = 0;
7010Sstevel@tonic-gate sz++;
7020Sstevel@tonic-gate req->request_url_len = sz;
7030Sstevel@tonic-gate req->request_url = off;
7040Sstevel@tonic-gate off += sz;
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate /*
7070Sstevel@tonic-gate * Set response length now as the scheme log function will
7080Sstevel@tonic-gate * subtract out any header length as we want the entity body
7090Sstevel@tonic-gate * length returned for the response_len.
7100Sstevel@tonic-gate */
7110Sstevel@tonic-gate req->response_len = (uint_t)suri->resplen;
7120Sstevel@tonic-gate
7130Sstevel@tonic-gate /* Call scheme log */
7140Sstevel@tonic-gate if (nl7c_http_log(quri, suri, req, &wp, &pep, &off)) goto full;
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate /* Update logbuf */
7170Sstevel@tonic-gate log->cur_pos = (wp - log->buffer);
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate req->response_status = HS_OK;
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate req->start_process_time = (time32_t)rtime;
7220Sstevel@tonic-gate req->end_process_time = (time32_t)gethrestime_sec();
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate req->remote_host = faddr;
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate ((nca_log_buf_hdr_t *)log)->nca_logstats.n_log_recs++;
7270Sstevel@tonic-gate mutex_exit(&log_lock);
7280Sstevel@tonic-gate return;
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate full:
7310Sstevel@tonic-gate /*
7320Sstevel@tonic-gate * The logbuf is full, zero fill from current
7330Sstevel@tonic-gate * write pointer through the end of the buf.
7340Sstevel@tonic-gate */
7350Sstevel@tonic-gate wp = (log->buffer + log->cur_pos);
7360Sstevel@tonic-gate sz = pep - wp;
7370Sstevel@tonic-gate bzero(wp, sz);
7380Sstevel@tonic-gate /*
7390Sstevel@tonic-gate * Link new logbuf onto end of logd and wake logd up.
7400Sstevel@tonic-gate */
7410Sstevel@tonic-gate mutex_enter(&logd.lock);
7420Sstevel@tonic-gate log->next = NULL;
7430Sstevel@tonic-gate if (logd.tail == NULL)
7440Sstevel@tonic-gate logd.head = log;
7450Sstevel@tonic-gate else
7460Sstevel@tonic-gate logd.tail->next = log;
7470Sstevel@tonic-gate logd.tail = log;
7480Sstevel@tonic-gate cv_signal(&logd.wait);
7490Sstevel@tonic-gate mutex_exit(&logd.lock);
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate * Try to allocate a new global logbuf.
7520Sstevel@tonic-gate */
7530Sstevel@tonic-gate log_buf_alloc(kmflag);
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate goto again;
7560Sstevel@tonic-gate }
757