Home | History | Annotate | Download | only in sockfs
      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
    169 log_buf_alloc(int kmflag)
    170 {
    171 	nca_log_buf_hdr_t	*hdr;
    172 	static	ulong_t		seq = 0;
    173 
    174 	ASSERT(mutex_owned(&log_lock));
    175 
    176 	if (logvcnt == 0) {
    177 		/*
    178 		 * No logv[] to use for the new log global logbuf,
    179 		 * try to allocate one or more before giving up.
    180 		 */
    181 		LOGBUFV_ALLOC(kmflag);
    182 		if (logvcnt == 0) {
    183 			/* No joy, just give up. */
    184 			log = NULL;
    185 			return;
    186 		}
    187 	}
    188 	log = logv[--logvcnt];
    189 
    190 	log->size = NCA_DEFAULT_LOG_BUF_SIZE;
    191 	log->cur_pos = sizeof (*hdr);
    192 
    193 	hdr = (nca_log_buf_hdr_t *)&log->buffer;
    194 	hdr->nca_loghdr.nca_version = NCA_LOG_VERSION1;
    195 	hdr->nca_loghdr.nca_op = log_op;
    196 	hdr->nca_logstats.n_log_size = NCA_DEFAULT_LOG_BUF_SIZE - sizeof (*hdr);
    197 	hdr->nca_logstats.n_log_recs = 0;
    198 	hdr->nca_logstats.n_log_upcall = seq++;
    199 
    200 	/* Try to allocate for at least the one we just used */
    201 	LOGBUFV_ALLOC(kmflag);
    202 }
    203 
    204 static void
    205 logd_off()
    206 {
    207 	;
    208 }
    209 
    210 static void
    211 logd_log_write(kmutex_t *lock, log_buf_t *lbp)
    212 {
    213 	nca_log_buf_hdr_t *hdr = (nca_log_buf_hdr_t *)lbp->buffer;
    214 	nca_log_stat_t	*sts = &hdr->nca_logstats;
    215 	int		size = sts->n_log_size + sizeof (*hdr);
    216 	vnode_t		*vp;
    217 	uio_t		uio;
    218 	iovec_t		iov;
    219 	int		ret;
    220 	boolean_t	noretry = B_FALSE;
    221 	vattr_t		attr;
    222 
    223 	if (size & (DEV_BSIZE - 1)) {
    224 		/*
    225 		 * Not appropriately sized for directio(),
    226 		 * add some filler so it is.
    227 		 */
    228 		sts->n_log_size += DEV_BSIZE - (size & (DEV_BSIZE - 1));
    229 		size = sts->n_log_size + sizeof (*hdr);
    230 	}
    231 retry:
    232 	if (nca_fio_offset(&fio) + size <= nca_fio_size(&fio)) {
    233 		/*
    234 		 * Room in the current log file so write the logbuf out,
    235 		 * exit the logd lock while doing the i/o as to not block
    236 		 * queuing.
    237 		 */
    238 		mutex_exit(lock);
    239 
    240 		vp = nca_fio_vp(&fio);
    241 		(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
    242 		iov.iov_base = lbp->buffer;
    243 		iov.iov_len = size;
    244 		uio.uio_iov = &iov;
    245 		uio.uio_iovcnt = 1;
    246 		uio.uio_segflg = UIO_SYSSPACE;
    247 		uio.uio_fmode = 0;
    248 		uio.uio_loffset = (u_offset_t)nca_fio_offset(&fio);
    249 		uio.uio_llimit = curproc->p_fsz_ctl;
    250 		uio.uio_resid = size;
    251 		ret = VOP_WRITE(vp, &uio, 0, kcred, NULL);
    252 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
    253 		if (ret != 0) {
    254 			if (ret == EFBIG) {
    255 				/*
    256 				 * Out of space for this file,
    257 				 * retry with the next.
    258 				 */
    259 				nca_fio_size(&fio) = nca_fio_offset(&fio);
    260 				if (noretry) {
    261 					nl7c_logd_enabled = B_FALSE;
    262 					goto done;
    263 				} else
    264 					goto next;
    265 			}
    266 		}
    267 		nca_fio_offset(&fio) = uio.uio_loffset;
    268 
    269 		mutex_enter(lock);
    270 		goto done;
    271 	}
    272 
    273 	/*
    274 	 * Current logfile doesn't have sufficient space
    275 	 * so move on to next file (if any).
    276 	 */
    277 next:
    278 	mutex_exit(lock);
    279 	/* Close current file */
    280 	ret = VOP_CLOSE(nca_fio_vp(&fio), FCREAT|FWRITE|FAPPEND|FTRUNC,
    281 			1, (offset_t)0, kcred, 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
    371 logd_worker(logd_t *logdp)
    372 {
    373 	log_buf_t	*lbp;
    374 	kmutex_t	*lock = &logdp->lock;
    375 	kcondvar_t	*wait = &logdp->wait;
    376 	callb_cpr_t	cprinfo;
    377 
    378 	CALLB_CPR_INIT(&cprinfo, lock, callb_generic_cpr, "nl7c");
    379 	mutex_enter(lock);
    380 
    381 	for (;;) {
    382 		/* Wait for something to do */
    383 		while ((lbp = logdp->head) == NULL) {
    384 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
    385 			cv_wait(wait, lock);
    386 			CALLB_CPR_SAFE_END(&cprinfo, lock);
    387 		}
    388 		if ((logdp->head = lbp->next) == NULL)
    389 			logdp->tail = NULL;
    390 		/* Got a logbuf to write out */
    391 		if (nl7c_logd_enabled)
    392 			logd_log_write(lock, lbp);
    393 		kmem_cache_free(log_buf_kmc, lbp);
    394 	}
    395 }
    396 
    397 boolean_t
    398 nl7c_logd_init(int fsz, caddr_t *fnv)
    399 {
    400 	vnode_t	*dvp;
    401 	vnode_t	*svp;
    402 	vnode_t	*vp;
    403 	int	ret;
    404 	caddr_t	*fnp;
    405 	vattr_t	attr;
    406 	uio_t	uio;
    407 	iovec_t	iov;
    408 	char	fbuf[TYPICALMAXPATHLEN + 1];
    409 
    410 	/*
    411 	 * Initialize the global logfio.
    412 	 */
    413 	nca_fio_cnt(&fio) = 0;
    414 	nca_fio_ix(&fio) = 0;
    415 	fnp = fnv;
    416 	while (*fnp != NULL) {
    417 		nca_fio_cnt(&fio)++;
    418 		nca_fio_name(&fio) = *fnp;
    419 		nca_fio_size(&fio) = fsz;
    420 		nca_fio_offset(&fio) = 0;
    421 		nca_fio_file(&fio) = nca_fio_ix(&fio);
    422 		nca_fio_vp(&fio) = NULL;
    423 
    424 		if (++fnp == &fnv[NCA_FIOV_SZ])
    425 			break;
    426 
    427 		nca_fio_ix(&fio)++;
    428 	}
    429 	/*
    430 	 * See if we can start logging from where we left off last time,
    431 	 * first check if the symlink exists.
    432 	 */
    433 	dvp = NULL;
    434 	ret = lookupname(symlink_path, UIO_SYSSPACE, NO_FOLLOW, &dvp, &svp);
    435 	if (ret || dvp == NULL || svp == NULL) {
    436 		if (dvp == NULL) {
    437 			/* No NCA symlink directory, create one */
    438 			attr.va_mask = AT_MODE | AT_TYPE;
    439 			attr.va_mode = 0755;
    440 			attr.va_type = VDIR;
    441 			ret = vn_create(symlink_dir, UIO_SYSSPACE, &attr,
    442 			    EXCL, 0, &dvp, CRMKDIR, 0, 0);
    443 			if (ret) {
    444 				cmn_err(CE_WARN, "nl7c_logd_init: create"
    445 				    " symlink dir of %s failed(%d).",
    446 				    symlink_dir, ret);
    447 				goto error;
    448 			}
    449 		}
    450 		nca_fio_dvp(&fio) = dvp;
    451 		/* No symlink so don't know were to start from */
    452 		goto fresh_start;
    453 	}
    454 	/* Save the symlink dir vnode */
    455 	nca_fio_dvp(&fio) = dvp;
    456 
    457 	/* Check if the file pointed by the symlink exists */
    458 	ret = lookupname(symlink_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
    459 	if (ret || vp == NULL)
    460 		goto fresh_start;
    461 	VN_RELE(vp);
    462 
    463 	/* Read the symlink and find it in fnv[], else fresh start */
    464 	iov.iov_len = TYPICALMAXPATHLEN;
    465 	iov.iov_base = fbuf;
    466 	uio.uio_iov = &iov;
    467 	uio.uio_iovcnt = 1;
    468 	uio.uio_resid = iov.iov_len;
    469 	uio.uio_segflg = UIO_SYSSPACE;
    470 	uio.uio_loffset = 0;
    471 	uio.uio_fmode = 0;
    472 	ret = VOP_READLINK(svp, &uio, kcred, 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
    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
    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