nl7clogd.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/pathname.h>
extern boolean_t nl7c_logd_enabled;
extern boolean_t nl7c_logd_started;
extern boolean_t nl7c_logd_cycle;
extern void nl7clogd_startup(void);
nca_request_log_t *, char **, char **, uint32_t *);
static void logit_flush(void *);
/*
* the symlink "current" to 1 of up to 16 NCA BLF logging files, by default
* a single logging file "log", optionally paths of up to 16 log files can
* be specified via ncalogd.conf(4), note that these log files need not be
*
* some future date (when NCA is deprecated or improvements are needed)
* these need to be moved into NL7C.
*
* NL7C implements logging differently in 2 ways, 1st the initialization
* is handled completely in the kernel by NL7C when it's enabled vs NCA
* when the kmod was loaded, 2nd a simple worker thread with a FIFO queue
* is used to process log_buf_t's instead of a squeue_t (this is done as
* squeue_t's are private to NCA and IP at some future date we may us an
* IP squeue_t):
*
* logd_t - used by various functions to manage a singly linked
* grounded list of log_buf_t's and it's worker thread.
*/
typedef struct logd_s {
} logd_t;
/*
* In-kernel logging:
*
* nl7c_logbuf_max - tunable for the number of preallocated next
* log_buf_t(s) for use by log_buf_alloc(), note if the value is
* 0 (the default) then max_cpus worth will be allocated.
*
* logd - global logd_t used to post log_buf_t's too.
*
* log - global current log_buf_t that logit() logs too.
*
* logv[] - vector of available next logbuf(s) such that when
* logbuf is filled another can be used while being processed by
* the logger() and kmem_cache_alloc() of a replacement is done.
*
* logvcnt - count of logv[] vector element(s) and the index
* plus 1 of the next logbuf.
*
*
* fio - the global nca_fio_t used to manage file i/o to a logfile.
*
* dir - path to the directory where the current logfile symlink
* is created and the default directory for logfile(s).
*
* symlink - name of the logfile symlink.
*
* symlink_path - path to the logfile symlink.
*
* log_lock - the kmutex_t used to guarantee atomic access of
* all of the above.
*
* flush_tid - logit_flush() timeout id.
*
* LOGBUFV_ALLOC() - macro used to add log_buf_t(s) to logv[].
*/
int nl7c_logbuf_max = 0;
static int logvcnt = 0;
static kmem_cache_t *log_buf_kmc;
static timeout_id_t flush_tid;
#define LOGBUFV_ALLOC(kmflag) { \
\
while (logvcnt < nl7c_logbuf_max) { \
/*CONSTCOND*/ \
mutex_exit(&log_lock); \
/*CONSTCOND*/ \
mutex_enter(&log_lock); \
if (logvcnt == nl7c_logbuf_max) { \
mutex_exit(&log_lock); \
mutex_enter(&log_lock); \
break; \
} \
} else { \
break; \
} \
} \
} \
}
/*
*/
static void
log_buf_alloc(int kmflag)
{
if (logvcnt == 0) {
/*
* No logv[] to use for the new log global logbuf,
* try to allocate one or more before giving up.
*/
if (logvcnt == 0) {
/* No joy, just give up. */
return;
}
}
/* Try to allocate for at least the one we just used */
}
static void
logd_off()
{
;
}
static void
{
int ret;
/*
* Not appropriately sized for directio(),
* add some filler so it is.
*/
}
/*
* Room in the current log file so write the logbuf out,
* exit the logd lock while doing the i/o as to not block
* queuing.
*/
if (ret != 0) {
/*
* Out of space for this file,
* retry with the next.
*/
if (noretry) {
goto done;
} else
goto next;
}
}
goto done;
}
/*
* Current logfile doesn't have sufficient space
* so move on to next file (if any).
*/
next:
/* Close current file */
if (ret) {
logd_off();
return;
}
/* Go to next file */
nca_fio_ix(&fio)++;
/*
* We have reached the last file. If cycling
* is not on, disable logging and bailout.
*/
if (nl7c_logd_cycle) {
/* Start from the first file */
nca_fio_ix(&fio) = 0;
} else {
nca_fio_ix(&fio)--;
logd_off();
return;
}
}
/* Open the next log file */
if (ret) {
logd_off();
return;
}
/* Turn on directio */
/* Start writing from the begining of the file */
nca_fio_offset(&fio) = 0;
/* Remove the current symlink */
/* Create symlink to the new log file */
if (ret) {
logd_off();
return;
}
goto retry;
done:
if (logvcnt < nl7c_logbuf_max) {
/* May need to allocate some logbuf(s) for logv[] */
if (logvcnt < nl7c_logbuf_max) {
/*
* After acquiring the lock still need logbuf(s),
* if the global logbuf pointer is NULL then call
* log_buf_alloc() as it will fill up logbugv[]
* and initialize a new logbuf else fill up just
* the logv[] here.
*/
} else {
/*LINTED*/
}
}
}
}
static void
{
for (;;) {
/* Wait for something to do */
}
/* Got a logbuf to write out */
if (nl7c_logd_enabled)
}
}
{
int ret;
/*
* Initialize the global logfio.
*/
nca_fio_cnt(&fio) = 0;
nca_fio_ix(&fio) = 0;
nca_fio_cnt(&fio)++;
nca_fio_offset(&fio) = 0;
break;
nca_fio_ix(&fio)++;
}
/*
* See if we can start logging from where we left off last time,
* first check if the symlink exists.
*/
/* No NCA symlink directory, create one */
if (ret) {
" symlink dir of %s failed(%d).",
symlink_dir, ret);
goto error;
}
}
/* No symlink so don't know were to start from */
goto fresh_start;
}
/* Save the symlink dir vnode */
/* Check if the file pointed by the symlink exists */
goto fresh_start;
/* Read the symlink and find it in fnv[], else fresh start */
uio.uio_loffset = 0;
if (ret) {
goto fresh_start;
}
/* Null terminate the buf */
nca_fio_ix(&fio) = 0;
break;
goto fresh_start;
nca_fio_ix(&fio)++;
}
goto fresh_start;
/* Start writing to the end of the file */
if (ret) {
goto error;
}
if (ret) {
goto error;
}
goto finish;
/*
* Here if no previous logging environment found or if the previous
* logging environment isn't usable or isn't consistent with the new
* fnv[]. Remove the existing symlink (if any) then create the new
* symlink to point to the first logfile.
*/
nca_fio_ix(&fio) = 0;
0);
if (ret) {
goto error;
}
if (ret) {
goto error;
}
/* Turn on directio */
if (nl7c_logbuf_max == 0)
}
/* Last, start logger timeout flush */
return (B_TRUE);
/*
* Error of some sort, free any resources in reverse order.
*/
nca_fio_ix(&fio) = 0;
nca_fio_ix(&fio)++;
}
nca_fio_cnt(&fio) = 0;
if (svp)
if (dvp)
return (B_FALSE);
}
/*ARGSUSED*/
static void
logit_flush(void *arg)
{
static int lastpos;
flush_tid = 0;
/* No global logbuf ? Nothing to flush. */
goto out;
}
/*
* We have a logbuf and it has log data and it's the
* same logbuf and pos as last time and after lock
* still true, so flush.
*/
/* Link new logbuf onto end of logd and wake logd up */
else
}
out:
/* Check again in 1 second */
}
void
{
char *wp;
char *pep;
int sz;
if (! nl7c_logd_enabled)
return;
if (! nl7c_logd_started) {
/* Startup logging */
}
/* No global logbuf, try to allocate one before giving up. */
/* No joy, just give up. */
return;
}
}
/*
* Get a pointer to an aligned write position, a pointer to past
* the end of the logbuf, and a pointer to the request header.
*
* As the request header is filled in field by field addtional
* storage is allcated following the request header.
*
* If at any point an allocation from the logbuf overflows (i.e.
* resulting in a pointer > pep) the current request logging is
* aborted, the current logbuf is posted for write, a new logbuf
* is allocated, and start all over.
*/
*wp++ = 0;
sz++;
/*
* Set response length now as the scheme log function will
* subtract out any header length as we want the entity body
* length returned for the response_len.
*/
/* Call scheme log */
/* Update logbuf */
return;
full:
/*
* The logbuf is full, zero fill from current
* write pointer through the end of the buf.
*/
/*
* Link new logbuf onto end of logd and wake logd up.
*/
else
/*
* Try to allocate a new global logbuf.
*/
goto again;
}