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 5*4155Sfr80241 * Common Development and Distribution License (the "License"). 6*4155Sfr80241 * 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 /* 22*4155Sfr80241 * 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 600Sstevel@tonic-gate * some future date (when NCA is depricated 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 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 2050Sstevel@tonic-gate logd_off() 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate ; 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate static void 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, 2810Sstevel@tonic-gate 1, (offset_t)0, kcred); 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, 3220Sstevel@tonic-gate DIRECTIO_ON, 0, kcred, 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 */ 3280Sstevel@tonic-gate (void) VOP_REMOVE(nca_fio_dvp(&fio), symlink, kcred); 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, 3360Sstevel@tonic-gate &attr, nca_fio_name(&fio), kcred); 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 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 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 } 450*4155Sfr80241 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; 4720Sstevel@tonic-gate ret = VOP_READLINK(svp, &uio, kcred); 4730Sstevel@tonic-gate if (ret) { 4740Sstevel@tonic-gate (void) VOP_REMOVE(dvp, symlink, kcred); 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; 5010Sstevel@tonic-gate (void) VOP_IOCTL(vp, _FIODIRECTIO, DIRECTIO_ON, 0, kcred, NULL); 5020Sstevel@tonic-gate attr.va_mask = AT_SIZE; 5030Sstevel@tonic-gate ret = VOP_GETATTR(nca_fio_vp(&fio), &attr, 0, 0); 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; 5230Sstevel@tonic-gate (void) VOP_REMOVE(dvp, symlink, kcred); 5240Sstevel@tonic-gate ret = VOP_SYMLINK(dvp, symlink, &attr, nca_fio_name(&fio), kcred); 5250Sstevel@tonic-gate if (ret) { 5260Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: symlink of %s to %s failed", 5270Sstevel@tonic-gate symlink_path, nca_fio_name(&fio)); 5280Sstevel@tonic-gate goto error; 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate ret = vn_open(nca_fio_name(&fio), UIO_SYSSPACE, 5310Sstevel@tonic-gate FCREAT|FWRITE|FTRUNC, 0600, &nca_fio_vp(&fio), 0, 0); 5320Sstevel@tonic-gate if (ret) { 5330Sstevel@tonic-gate cmn_err(CE_WARN, "nl7c_logd_init: vn_open of " 5340Sstevel@tonic-gate "%s failed (error %d)", nca_fio_name(&fio), ret); 5350Sstevel@tonic-gate goto error; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* Turn on directio */ 5390Sstevel@tonic-gate (void) VOP_IOCTL(nca_fio_vp(&fio), _FIODIRECTIO, 5400Sstevel@tonic-gate DIRECTIO_ON, 0, kcred, NULL); 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate finish: 5430Sstevel@tonic-gate log_buf_kmc = kmem_cache_create("NL7C_log_buf_kmc", sizeof (log_buf_t), 5440Sstevel@tonic-gate 0, NULL, NULL, NULL, NULL, NULL, 0); 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate mutex_init(&log_lock, NULL, MUTEX_DEFAULT, NULL); 5470Sstevel@tonic-gate mutex_enter(&log_lock); 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate if (nl7c_logbuf_max == 0) 5500Sstevel@tonic-gate nl7c_logbuf_max = max_ncpus; 5510Sstevel@tonic-gate logv = kmem_alloc(nl7c_logbuf_max * sizeof (*logv), KM_SLEEP); 5520Sstevel@tonic-gate for (logvcnt = 0; logvcnt < nl7c_logbuf_max; logvcnt++) { 5530Sstevel@tonic-gate logv[logvcnt] = kmem_cache_alloc(log_buf_kmc, KM_SLEEP); 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate log_buf_alloc(KM_SLEEP); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate mutex_init(&logd.lock, NULL, MUTEX_DEFAULT, NULL); 5590Sstevel@tonic-gate cv_init(&logd.wait, NULL, CV_DEFAULT, NULL); 5600Sstevel@tonic-gate logd.head = NULL; 5610Sstevel@tonic-gate logd.tail = NULL; 5620Sstevel@tonic-gate logd.worker = thread_create(NULL, 0, logd_worker, &logd, 5630Sstevel@tonic-gate 0, &p0, TS_RUN, maxclsyspri); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate mutex_exit(&log_lock); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate /* Last, start logger timeout flush */ 5680Sstevel@tonic-gate logit_flush(NULL); 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate return (B_TRUE); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * Error of some sort, free any resources in reverse order. 5740Sstevel@tonic-gate */ 5750Sstevel@tonic-gate error: 5760Sstevel@tonic-gate nca_fio_ix(&fio) = 0; 5770Sstevel@tonic-gate while (nca_fio_ix(&fio) < nca_fio_cnt(&fio)) { 5780Sstevel@tonic-gate char *name = nca_fio_name(&fio); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if ((vp = nca_fio_vp(&fio)) != NULL) 5810Sstevel@tonic-gate VN_RELE(vp); 5820Sstevel@tonic-gate kmem_free(name, strlen(name)); 5830Sstevel@tonic-gate nca_fio_ix(&fio)++; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate nca_fio_cnt(&fio) = 0; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate if (svp) 5880Sstevel@tonic-gate VN_RELE(svp); 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (dvp) 5910Sstevel@tonic-gate VN_RELE(dvp); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate return (B_FALSE); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /*ARGSUSED*/ 5970Sstevel@tonic-gate static void 5980Sstevel@tonic-gate logit_flush(void *arg) 5990Sstevel@tonic-gate { 6000Sstevel@tonic-gate static log_buf_t *lastlbp = NULL; 6010Sstevel@tonic-gate static int lastpos; 6020Sstevel@tonic-gate log_buf_t *lbp = log; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate flush_tid = 0; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate mutex_enter(&log_lock); 6070Sstevel@tonic-gate if (log == NULL) { 6080Sstevel@tonic-gate /* No global logbuf ? Nothing to flush. */ 6090Sstevel@tonic-gate goto out; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate if (lbp != NULL && lbp->cur_pos > (sizeof (nca_log_buf_hdr_t)) && 6120Sstevel@tonic-gate lastlbp == lbp && lastpos == lbp->cur_pos) { 6130Sstevel@tonic-gate /* 6140Sstevel@tonic-gate * We have a logbuf and it has log data and it's the 6150Sstevel@tonic-gate * same logbuf and pos as last time and after lock 6160Sstevel@tonic-gate * still true, so flush. 6170Sstevel@tonic-gate */ 6180Sstevel@tonic-gate nca_log_stat_t *sp; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate sp = &(((nca_log_buf_hdr_t *)lbp)->nca_logstats); 6210Sstevel@tonic-gate sp->n_log_size = lbp->cur_pos; 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* Link new logbuf onto end of logd and wake logd up */ 6240Sstevel@tonic-gate mutex_enter(&logd.lock); 6250Sstevel@tonic-gate log->next = NULL; 6260Sstevel@tonic-gate if (logd.tail == NULL) 6270Sstevel@tonic-gate logd.head = log; 6280Sstevel@tonic-gate else 6290Sstevel@tonic-gate logd.tail->next = log; 6300Sstevel@tonic-gate logd.tail = log; 6310Sstevel@tonic-gate cv_signal(&logd.wait); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate mutex_exit(&logd.lock); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate log_buf_alloc(KM_NOSLEEP); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate if ((lastlbp = lbp) != NULL) 6390Sstevel@tonic-gate lastpos = lbp->cur_pos; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate mutex_exit(&log_lock); 6420Sstevel@tonic-gate out: 6430Sstevel@tonic-gate /* Check again in 1 second */ 6440Sstevel@tonic-gate flush_tid = timeout(&logit_flush, NULL, hz); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate void 6480Sstevel@tonic-gate nl7c_logd_log(uri_desc_t *quri, uri_desc_t *suri, time_t rtime, ipaddr_t faddr) 6490Sstevel@tonic-gate { 6500Sstevel@tonic-gate nca_request_log_t *req; 6510Sstevel@tonic-gate char *wp; 6520Sstevel@tonic-gate char *pep; 6530Sstevel@tonic-gate int sz; 6540Sstevel@tonic-gate uint32_t off = 0; 6550Sstevel@tonic-gate int kmflag = servicing_interrupt() ? KM_NOSLEEP : KM_SLEEP; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if (! nl7c_logd_enabled) 6580Sstevel@tonic-gate return; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate if (! nl7c_logd_started) { 6610Sstevel@tonic-gate /* Startup logging */ 6620Sstevel@tonic-gate nl7clogd_startup(); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate mutex_enter(&log_lock); 6650Sstevel@tonic-gate again: 6660Sstevel@tonic-gate if (log == NULL) { 6670Sstevel@tonic-gate /* No global logbuf, try to allocate one before giving up. */ 6680Sstevel@tonic-gate log_buf_alloc(kmflag); 6690Sstevel@tonic-gate if (log == NULL) { 6700Sstevel@tonic-gate /* No joy, just give up. */ 6710Sstevel@tonic-gate mutex_exit(&log_lock); 6720Sstevel@tonic-gate return; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate /* 6760Sstevel@tonic-gate * Get a pointer to an aligned write position, a pointer to past 6770Sstevel@tonic-gate * the end of the logbuf, and a pointer to the request header. 6780Sstevel@tonic-gate * 6790Sstevel@tonic-gate * As the request header is filled in field by field addtional 6800Sstevel@tonic-gate * storage is allcated following the request header. 6810Sstevel@tonic-gate * 6820Sstevel@tonic-gate * If at any point an allocation from the logbuf overflows (i.e. 6830Sstevel@tonic-gate * resulting in a pointer > pep) the current request logging is 6840Sstevel@tonic-gate * aborted, the current logbuf is posted for write, a new logbuf 6850Sstevel@tonic-gate * is allocated, and start all over. 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate pep = &((char *)log)[log->size]; 6880Sstevel@tonic-gate wp = (log->buffer + log->cur_pos); 6890Sstevel@tonic-gate wp = NCA_LOG_ALIGN(wp); 6900Sstevel@tonic-gate req = (nca_request_log_t *)wp; 6910Sstevel@tonic-gate if ((wp + sizeof (*req)) >= pep) goto full; 6920Sstevel@tonic-gate bzero(wp, sizeof (*req)); 6930Sstevel@tonic-gate wp += sizeof (*req); 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate sz = MIN((quri->path.ep - quri->path.cp), MAX_URL_LEN); 6960Sstevel@tonic-gate if ((wp + sz + 1) >= pep) goto full; 6970Sstevel@tonic-gate bcopy(quri->path.cp, wp, sz); 6980Sstevel@tonic-gate wp += sz; 6990Sstevel@tonic-gate *wp++ = 0; 7000Sstevel@tonic-gate sz++; 7010Sstevel@tonic-gate req->request_url_len = sz; 7020Sstevel@tonic-gate req->request_url = off; 7030Sstevel@tonic-gate off += sz; 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * Set response length now as the scheme log function will 7070Sstevel@tonic-gate * subtract out any header length as we want the entity body 7080Sstevel@tonic-gate * length returned for the response_len. 7090Sstevel@tonic-gate */ 7100Sstevel@tonic-gate req->response_len = (uint_t)suri->resplen; 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate /* Call scheme log */ 7130Sstevel@tonic-gate if (nl7c_http_log(quri, suri, req, &wp, &pep, &off)) goto full; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate /* Update logbuf */ 7160Sstevel@tonic-gate log->cur_pos = (wp - log->buffer); 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate req->response_status = HS_OK; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate req->start_process_time = (time32_t)rtime; 7210Sstevel@tonic-gate req->end_process_time = (time32_t)gethrestime_sec(); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate req->remote_host = faddr; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate ((nca_log_buf_hdr_t *)log)->nca_logstats.n_log_recs++; 7260Sstevel@tonic-gate mutex_exit(&log_lock); 7270Sstevel@tonic-gate return; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate full: 7300Sstevel@tonic-gate /* 7310Sstevel@tonic-gate * The logbuf is full, zero fill from current 7320Sstevel@tonic-gate * write pointer through the end of the buf. 7330Sstevel@tonic-gate */ 7340Sstevel@tonic-gate wp = (log->buffer + log->cur_pos); 7350Sstevel@tonic-gate sz = pep - wp; 7360Sstevel@tonic-gate bzero(wp, sz); 7370Sstevel@tonic-gate /* 7380Sstevel@tonic-gate * Link new logbuf onto end of logd and wake logd up. 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate mutex_enter(&logd.lock); 7410Sstevel@tonic-gate log->next = NULL; 7420Sstevel@tonic-gate if (logd.tail == NULL) 7430Sstevel@tonic-gate logd.head = log; 7440Sstevel@tonic-gate else 7450Sstevel@tonic-gate logd.tail->next = log; 7460Sstevel@tonic-gate logd.tail = log; 7470Sstevel@tonic-gate cv_signal(&logd.wait); 7480Sstevel@tonic-gate mutex_exit(&logd.lock); 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Try to allocate a new global logbuf. 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate log_buf_alloc(kmflag); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate goto again; 7550Sstevel@tonic-gate } 756