xref: /onnv-gate/usr/src/uts/common/fs/nfs/nfs_log.c (revision 12081:09a9f049d88e)
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
51610Sthurlow  * Common Development and Distribution License (the "License").
61610Sthurlow  * 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*12081SThomas.Haynes@Sun.COM  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/cred.h>
260Sstevel@tonic-gate #include <sys/cmn_err.h>
270Sstevel@tonic-gate #include <sys/debug.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/kmem.h>
300Sstevel@tonic-gate #include <sys/disp.h>
310Sstevel@tonic-gate #include <sys/atomic.h>
320Sstevel@tonic-gate #include <rpc/types.h>
330Sstevel@tonic-gate #include <nfs/nfs.h>
340Sstevel@tonic-gate #include <nfs/nfssys.h>
350Sstevel@tonic-gate #include <nfs/export.h>
360Sstevel@tonic-gate #include <nfs/rnode.h>
370Sstevel@tonic-gate #include <rpc/auth.h>
380Sstevel@tonic-gate #include <rpc/svc.h>
390Sstevel@tonic-gate #include <rpc/xdr.h>
400Sstevel@tonic-gate #include <rpc/clnt.h>
410Sstevel@tonic-gate #include <nfs/nfs_log.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #define	NUM_RECORDS_TO_WRITE 256
440Sstevel@tonic-gate #define	NUM_BYTES_TO_WRITE 65536
450Sstevel@tonic-gate 
460Sstevel@tonic-gate extern krwlock_t exported_lock;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static int nfslog_num_records_to_write = NUM_RECORDS_TO_WRITE;
490Sstevel@tonic-gate static int nfslog_num_bytes_to_write = NUM_BYTES_TO_WRITE;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * This struct is used to 'hide' the details of managing the log
530Sstevel@tonic-gate  * records internally to the logging code.  Allocation routines
540Sstevel@tonic-gate  * are used to obtain pieces of memory for XDR encoding.  This struct
550Sstevel@tonic-gate  * is a 'header' to those areas and a opaque cookie is used to pass
560Sstevel@tonic-gate  * this data structure between the allocating function and the put
570Sstevel@tonic-gate  * function.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate struct lr_alloc {
600Sstevel@tonic-gate 	struct lr_alloc		*next;		/* links for write queuing */
610Sstevel@tonic-gate 	struct lr_alloc		*prev;
620Sstevel@tonic-gate #define	LR_ALLOC_NOFREE	0x1			/* not present, call free */
630Sstevel@tonic-gate 	int			lr_flags;
640Sstevel@tonic-gate 	caddr_t			log_record;	/* address to XDR encoding */
650Sstevel@tonic-gate 	size_t			size;		/* final size of encoding */
660Sstevel@tonic-gate 	struct kmem_cache	*alloc_cache;	/* keep track of cache ptr */
670Sstevel@tonic-gate 	struct exportinfo	*exi;		/* who are we related to? */
680Sstevel@tonic-gate 	struct log_buffer	*lb;
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate struct flush_thread_params {
720Sstevel@tonic-gate 	struct nfsl_flush_args tp_args;
730Sstevel@tonic-gate 	int tp_error;
740Sstevel@tonic-gate };
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static int log_file_create(caddr_t, struct log_file **);
770Sstevel@tonic-gate static void log_file_rele(struct log_file *);
780Sstevel@tonic-gate static struct log_buffer *log_buffer_create(caddr_t);
790Sstevel@tonic-gate static void log_buffer_rele(struct log_buffer *);
800Sstevel@tonic-gate static int nfslog_record_append2all(struct lr_alloc *);
810Sstevel@tonic-gate static int nfslog_logbuffer_rename(struct log_buffer *);
820Sstevel@tonic-gate static void nfslog_logfile_wait(struct log_file *);
830Sstevel@tonic-gate static int nfslog_logfile_rename(char *, char *);
840Sstevel@tonic-gate static void nfslog_do_flush(struct flush_thread_params *);
850Sstevel@tonic-gate static void create_buffer_header(caddr_t *, size_t *, size_t *);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static int nfslog_write_logrecords(struct log_file *, struct lr_alloc *, int);
880Sstevel@tonic-gate static void nfslog_free_logrecords(struct lr_alloc *);
890Sstevel@tonic-gate static int nfslog_records_flush_to_disk(struct log_buffer *);
900Sstevel@tonic-gate static int nfslog_records_flush_to_disk_nolock(struct log_buffer *);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * Read/Write lock that protects 'nfslog_buffer_list'.
940Sstevel@tonic-gate  * This lock must be held when searching or modifying 'nfslog_buffer_list'.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate static krwlock_t nfslog_buffer_list_lock;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * The list of "log_buffer" structures.
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate struct log_buffer *nfslog_buffer_list = NULL;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #define	LOG_BUFFER_HOLD(lbp)	{ \
1050Sstevel@tonic-gate 	mutex_enter(&(lbp)->lb_lock); \
1060Sstevel@tonic-gate 	(lbp)->lb_refcnt++; \
1070Sstevel@tonic-gate 	mutex_exit(&(lbp)->lb_lock); \
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate #define	LOG_FILE_HOLD(lfp)	{ \
1110Sstevel@tonic-gate 	mutex_enter(&(lfp)->lf_lock); \
1120Sstevel@tonic-gate 	(lfp)->lf_refcnt++; \
1130Sstevel@tonic-gate 	mutex_exit(&(lfp)->lf_lock); \
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate #define	LOG_FILE_RELE(lfp)	{ \
1170Sstevel@tonic-gate 	log_file_rele(lfp); \
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  * These two macros are used to prep a logfile data structure and
1220Sstevel@tonic-gate  * associated file for writing data.  Note that the lf_lock is
1230Sstevel@tonic-gate  * held as a result of the call to the first macro.  This is used
1240Sstevel@tonic-gate  * for serialization correctness between the logbuffer struct and
1250Sstevel@tonic-gate  * the logfile struct.
1260Sstevel@tonic-gate  */
1270Sstevel@tonic-gate #define	LOG_FILE_LOCK_TO_WRITE(lfp)	{ \
1280Sstevel@tonic-gate 	mutex_enter(&(lfp)->lf_lock); \
1290Sstevel@tonic-gate 	(lfp)->lf_refcnt++; \
1300Sstevel@tonic-gate 	(lfp)->lf_writers++; \
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate #define	LOG_FILE_UNLOCK_FROM_WRITE(lfp)	{ \
1340Sstevel@tonic-gate 	(lfp)->lf_writers--; \
1350Sstevel@tonic-gate 	if ((lfp)->lf_writers == 0 && ((lfp)->lf_flags & L_WAITING)) { \
1360Sstevel@tonic-gate 		(lfp)->lf_flags &= ~L_WAITING; \
1370Sstevel@tonic-gate 		cv_broadcast(&(lfp)->lf_cv_waiters); \
1380Sstevel@tonic-gate 	} \
1390Sstevel@tonic-gate 	mutex_exit(&(lfp)->lf_lock); \
1400Sstevel@tonic-gate 	log_file_rele(lfp); \
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int rfsl_log_buffer = 0;
1440Sstevel@tonic-gate static int rfsl_log_file = 0;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /* This array is used for memory allocation of record encoding spaces */
1470Sstevel@tonic-gate static struct {
1480Sstevel@tonic-gate 	int	size;
1490Sstevel@tonic-gate 	struct kmem_cache *mem_cache;
1500Sstevel@tonic-gate 	char	*cache_name;
1510Sstevel@tonic-gate } nfslog_mem_alloc[] = {
1520Sstevel@tonic-gate #define	SMALL_INDX 0
1530Sstevel@tonic-gate 	{ NFSLOG_SMALL_RECORD_SIZE - sizeof (struct lr_alloc),
1540Sstevel@tonic-gate 	NULL, NFSLOG_SMALL_REC_NAME },
1550Sstevel@tonic-gate #define	MEDIUM_INDX 1
1560Sstevel@tonic-gate 	{ NFSLOG_MEDIUM_RECORD_SIZE - sizeof (struct lr_alloc),
1570Sstevel@tonic-gate 	NULL, NFSLOG_MEDIUM_REC_NAME },
1580Sstevel@tonic-gate #define	LARGE_INDX 2
1590Sstevel@tonic-gate 	{ NFSLOG_LARGE_RECORD_SIZE - sizeof (struct lr_alloc),
1600Sstevel@tonic-gate 	NULL, NFSLOG_LARGE_REC_NAME },
1610Sstevel@tonic-gate 	{ (-1), NULL }
1620Sstevel@tonic-gate };
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /* Used to calculate the 'real' allocation size */
1650Sstevel@tonic-gate #define	ALLOC_SIZE(index) \
1660Sstevel@tonic-gate 	(nfslog_mem_alloc[index].size + sizeof (struct lr_alloc))
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*
1690Sstevel@tonic-gate  * Initialize logging data buffer cache
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate void
nfslog_init()1720Sstevel@tonic-gate nfslog_init()
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	int indx;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	rw_init(&nfslog_buffer_list_lock, NULL, RW_DEFAULT, NULL);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/*
1790Sstevel@tonic-gate 	 * Initialize the kmem caches for encoding
1800Sstevel@tonic-gate 	 */
1810Sstevel@tonic-gate 	for (indx = 0; nfslog_mem_alloc[indx].size != (-1); indx++) {
1820Sstevel@tonic-gate 		nfslog_mem_alloc[indx].mem_cache =
1835112Sbatschul 		    kmem_cache_create(nfslog_mem_alloc[indx].cache_name,
1845112Sbatschul 		    ALLOC_SIZE(indx), 0, NULL, NULL, NULL, NULL, NULL, 0);
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * Sets up the necessary log file and related buffers to enable logging
1900Sstevel@tonic-gate  * on the given export point.
1910Sstevel@tonic-gate  * Returns 0 on success, non-zero on failure.
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate int
nfslog_setup(struct exportinfo * exi)1940Sstevel@tonic-gate nfslog_setup(struct exportinfo *exi)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	struct exportdata *kex;
1970Sstevel@tonic-gate 	struct log_buffer *lbp;
1980Sstevel@tonic-gate 	struct log_buffer *nlbp;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	kex = &exi->exi_export;
2010Sstevel@tonic-gate 	ASSERT(kex->ex_flags & EX_LOG);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * Logging is enabled for the new export point, check
2050Sstevel@tonic-gate 	 * the existing log_buffer structures to see if the
2060Sstevel@tonic-gate 	 * desired buffer has already been opened. If so, point
2070Sstevel@tonic-gate 	 * the new exportinfo's exi_logbuffer to the existing
2080Sstevel@tonic-gate 	 * one.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	rw_enter(&nfslog_buffer_list_lock, RW_READER);
2110Sstevel@tonic-gate 	for (lbp = nfslog_buffer_list; lbp != NULL; lbp = lbp->lb_next) {
2120Sstevel@tonic-gate 		LOGGING_DPRINT((10,
2130Sstevel@tonic-gate 		    "searching for buffer... found log_buffer '%s'\n",
2145112Sbatschul 		    lbp->lb_path));
2150Sstevel@tonic-gate 		if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) {
2160Sstevel@tonic-gate 			/* Found our match. Ref it and return */
2170Sstevel@tonic-gate 			LOG_BUFFER_HOLD(lbp);
2180Sstevel@tonic-gate 			exi->exi_logbuffer = lbp;
2190Sstevel@tonic-gate 			LOGGING_DPRINT((10,  "\tfound log_buffer for '%s'\n",
2205112Sbatschul 			    kex->ex_log_buffer));
2210Sstevel@tonic-gate 			rw_exit(&nfslog_buffer_list_lock);
2220Sstevel@tonic-gate 			return (0);
2230Sstevel@tonic-gate 		}
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 	rw_exit(&nfslog_buffer_list_lock);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	/*
2280Sstevel@tonic-gate 	 * New buffer needed, allocate it.
2290Sstevel@tonic-gate 	 * The buffer list lock has been dropped so we will need to search
2300Sstevel@tonic-gate 	 * the list again to ensure that another thread has not added
2310Sstevel@tonic-gate 	 * a matching buffer.
2320Sstevel@tonic-gate 	 */
2330Sstevel@tonic-gate 	if ((nlbp = log_buffer_create(kex->ex_log_buffer)) == NULL) {
2340Sstevel@tonic-gate 		/*
2350Sstevel@tonic-gate 		 * Failed the buffer creation for some reason so we
2360Sstevel@tonic-gate 		 * will need to return.
2370Sstevel@tonic-gate 		 */
2380Sstevel@tonic-gate 		return (EIO);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	rw_enter(&nfslog_buffer_list_lock, RW_WRITER);
2420Sstevel@tonic-gate 	for (lbp = nfslog_buffer_list; lbp != NULL;
2435112Sbatschul 	    lbp = lbp->lb_next) {
2440Sstevel@tonic-gate 		if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) {
2450Sstevel@tonic-gate 				/*
2460Sstevel@tonic-gate 				 * A log_buffer already exists for the
2470Sstevel@tonic-gate 				 * indicated buffer, use it instead.
2480Sstevel@tonic-gate 				 */
2490Sstevel@tonic-gate 			LOG_BUFFER_HOLD(lbp);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 			exi->exi_logbuffer = lbp;
2520Sstevel@tonic-gate 
2535112Sbatschul 			LOGGING_DPRINT((10, "found log_buffer for '%s' "
2545112Sbatschul 			    "after allocation\n", kex->ex_log_buffer));
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 			rw_exit(&nfslog_buffer_list_lock);
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 			log_buffer_rele(nlbp);
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 			return (0);
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 	}
2630Sstevel@tonic-gate 	/*
2640Sstevel@tonic-gate 	 * Didn't find an existing log_buffer for this buffer,
2650Sstevel@tonic-gate 	 * use the the newly created one, and add to list.  We
2660Sstevel@tonic-gate 	 * increment the reference count because the node is
2670Sstevel@tonic-gate 	 * entered into the global list.
2680Sstevel@tonic-gate 	 */
2697240Srh87107 	LOGGING_DPRINT((10, "exportfs: adding nlbp=%p to list\n",
2707240Srh87107 	    (void *)nlbp));
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	nlbp->lb_next = nfslog_buffer_list;
2730Sstevel@tonic-gate 	nfslog_buffer_list = nlbp;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	LOG_BUFFER_HOLD(nlbp);	/* hold is for export entry */
2760Sstevel@tonic-gate 	exi->exi_logbuffer = nlbp;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	rw_exit(&nfslog_buffer_list_lock);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return (0);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * Disables logging for the given export point.
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate void
nfslog_disable(struct exportinfo * exi)2870Sstevel@tonic-gate nfslog_disable(struct exportinfo *exi)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	log_buffer_rele(exi->exi_logbuffer);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * Creates the corresponding log_buffer and log_file structures
2940Sstevel@tonic-gate  * for the the buffer named 'name'.
2950Sstevel@tonic-gate  * Returns a pointer to the log_buffer structure with reference one.
2960Sstevel@tonic-gate  */
2970Sstevel@tonic-gate static struct log_buffer *
log_buffer_create(caddr_t name)2980Sstevel@tonic-gate log_buffer_create(caddr_t name)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	struct log_buffer *buffer;
3010Sstevel@tonic-gate 	struct log_file *logfile;
3020Sstevel@tonic-gate 	int namelen = strlen(name);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	LOGGING_DPRINT((10,  "log_buffer_create: %s\n", name));
3050Sstevel@tonic-gate 	if (log_file_create(name, &logfile))
3060Sstevel@tonic-gate 		return (NULL);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	buffer = (struct log_buffer *)kmem_alloc(sizeof (*buffer), KM_SLEEP);
3090Sstevel@tonic-gate 	buffer->lb_refcnt = 1;
3100Sstevel@tonic-gate 	buffer->lb_rec_id = 0;
3110Sstevel@tonic-gate 	buffer->lb_path = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP);
3120Sstevel@tonic-gate 	bcopy(name, buffer->lb_path, namelen + 1);
3130Sstevel@tonic-gate 	buffer->lb_logfile = logfile;
3140Sstevel@tonic-gate 	buffer->lb_records = NULL;
3150Sstevel@tonic-gate 	buffer->lb_num_recs = 0;
3160Sstevel@tonic-gate 	buffer->lb_size_queued = 0;
3170Sstevel@tonic-gate 	mutex_init(&buffer->lb_lock, NULL, MUTEX_DEFAULT, NULL);
3180Sstevel@tonic-gate 	rfsl_log_buffer++;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	return (buffer);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate  * Release a log_buffer structure
3250Sstevel@tonic-gate  */
3260Sstevel@tonic-gate static void
log_buffer_rele(struct log_buffer * lbp)3270Sstevel@tonic-gate log_buffer_rele(struct log_buffer *lbp)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	int len;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	mutex_enter(&lbp->lb_lock);
3320Sstevel@tonic-gate 	if (--lbp->lb_refcnt > 1) {
3330Sstevel@tonic-gate 		mutex_exit(&lbp->lb_lock);
3340Sstevel@tonic-gate 		return;
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	if (lbp->lb_refcnt < 0) {
3380Sstevel@tonic-gate 		panic("log_rele: log_buffer refcnt < 0");
3390Sstevel@tonic-gate 		/*NOTREACHED*/
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/*
3430Sstevel@tonic-gate 	 * Need to drop the lb_lock before acquiring the
3440Sstevel@tonic-gate 	 * nfslog_buffer_list_lock. To avoid double free we need
3450Sstevel@tonic-gate 	 * to hold an additional reference to the log buffer.
3460Sstevel@tonic-gate 	 * This will ensure that no two threads will simultaneously
3470Sstevel@tonic-gate 	 * be trying to free the same log buffer.
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if (lbp->lb_refcnt == 1) {
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		/*
3530Sstevel@tonic-gate 		 * If the ref count is 1, then the last
3540Sstevel@tonic-gate 		 * unshare/reference has been given up and we need to
3550Sstevel@tonic-gate 		 * clean up the buffer and remove it from the buffer
3560Sstevel@tonic-gate 		 * list.
3570Sstevel@tonic-gate 		 */
3580Sstevel@tonic-gate 		LOGGING_DPRINT((10,
3597240Srh87107 		    "log_buffer_rele lbp=%p disconnecting\n", (void *)lbp));
3600Sstevel@tonic-gate 		/*
3610Sstevel@tonic-gate 		 * Hold additional reference before dropping the lb_lock
3620Sstevel@tonic-gate 		 */
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		lbp->lb_refcnt++;
3650Sstevel@tonic-gate 		mutex_exit(&lbp->lb_lock);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 		/*
3680Sstevel@tonic-gate 		 * Make sure that all of the buffered records are written.
3690Sstevel@tonic-gate 		 * Don't bother checking the write return value since there
3700Sstevel@tonic-gate 		 * isn't much we can do at this point.
3710Sstevel@tonic-gate 		 */
3720Sstevel@tonic-gate 		(void) nfslog_records_flush_to_disk(lbp);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		rw_enter(&nfslog_buffer_list_lock, RW_WRITER);
3750Sstevel@tonic-gate 		mutex_enter(&lbp->lb_lock);
3760Sstevel@tonic-gate 		/*
3770Sstevel@tonic-gate 		 * Drop the reference count held above.
3780Sstevel@tonic-gate 		 * If the ref count is still > 1 then someone has
3790Sstevel@tonic-gate 		 * stepped in to use this log buffer.  unlock and return.
3800Sstevel@tonic-gate 		 */
3810Sstevel@tonic-gate 		if (--lbp->lb_refcnt > 1) {
3820Sstevel@tonic-gate 			mutex_exit(&lbp->lb_lock);
3830Sstevel@tonic-gate 			rw_exit(&nfslog_buffer_list_lock);
3840Sstevel@tonic-gate 			return;
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 		if (lbp == nfslog_buffer_list) {
3880Sstevel@tonic-gate 			nfslog_buffer_list = lbp->lb_next;
3890Sstevel@tonic-gate 		} else {
3900Sstevel@tonic-gate 			struct log_buffer *tlbp;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 			/* Drop the log_buffer from the master list */
3930Sstevel@tonic-gate 			for (tlbp = nfslog_buffer_list; tlbp->lb_next != NULL;
3945112Sbatschul 			    tlbp = tlbp->lb_next) {
3950Sstevel@tonic-gate 				if (tlbp->lb_next == lbp) {
3960Sstevel@tonic-gate 					tlbp->lb_next = lbp->lb_next;
3970Sstevel@tonic-gate 					break;
3980Sstevel@tonic-gate 				}
3990Sstevel@tonic-gate 			}
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		mutex_exit(&lbp->lb_lock);
4030Sstevel@tonic-gate 		rw_exit(&nfslog_buffer_list_lock);
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * ref count zero; finish clean up.
4070Sstevel@tonic-gate 	 */
4087240Srh87107 	LOGGING_DPRINT((10, "log_buffer_rele lbp=%p freeing\n", (void *)lbp));
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	log_file_rele(lbp->lb_logfile);
4110Sstevel@tonic-gate 	len = strlen(lbp->lb_path) + 1;
4120Sstevel@tonic-gate 	kmem_free(lbp->lb_path, len);
4130Sstevel@tonic-gate 	kmem_free(lbp, sizeof (*lbp));
4140Sstevel@tonic-gate 	rfsl_log_buffer--;
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate  * Creates the corresponding log_file structure for the buffer
4190Sstevel@tonic-gate  * named 'log_file_name'.
4200Sstevel@tonic-gate  * 'log_file_name' is created by concatenating 'origname' and LOG_INPROG_STRING.
4210Sstevel@tonic-gate  * 'logfile' is set to be the log_file structure with reference one.
4220Sstevel@tonic-gate  */
4230Sstevel@tonic-gate static int
log_file_create(caddr_t origname,struct log_file ** lfpp)4240Sstevel@tonic-gate log_file_create(caddr_t origname, struct log_file **lfpp)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	vnode_t *vp = NULL;
4270Sstevel@tonic-gate 	char *name;
4280Sstevel@tonic-gate 	int namelen;
4290Sstevel@tonic-gate 	int error;
4300Sstevel@tonic-gate 	struct log_file *logfile = NULL;
4310Sstevel@tonic-gate 	vattr_t va;
4320Sstevel@tonic-gate 	caddr_t loghdr = NULL;
4330Sstevel@tonic-gate 	size_t loghdr_len = 0;
4340Sstevel@tonic-gate 	size_t loghdr_free = 0;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	namelen = strlen(origname) + strlen(LOG_INPROG_STRING);
4370Sstevel@tonic-gate 	name = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP);
4380Sstevel@tonic-gate 	(void) sprintf(name, "%s%s", origname, LOG_INPROG_STRING);
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	LOGGING_DPRINT((3, "log_file_create: %s\n", name));
4410Sstevel@tonic-gate 	if (error = vn_open(name, UIO_SYSSPACE, FCREAT|FWRITE|FOFFMAX,
4425112Sbatschul 	    LOG_MODE, &vp, CRCREAT, 0)) {
4430Sstevel@tonic-gate 		nfs_cmn_err(error, CE_WARN,
4445112Sbatschul 		    "log_file_create: Can not open %s - error %m", name);
4450Sstevel@tonic-gate 		goto out;
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 	LOGGING_DPRINT((3, "log_file_create: %s vp=%p v_count=%d\n",
4487240Srh87107 	    name, (void *)vp, vp->v_count));
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	logfile = (struct log_file *)kmem_zalloc(sizeof (*logfile), KM_SLEEP);
4510Sstevel@tonic-gate 	logfile->lf_path = name;
4520Sstevel@tonic-gate 	/*
4530Sstevel@tonic-gate 	 * No need to bump the vnode reference count since it is set
4540Sstevel@tonic-gate 	 * to one by vn_open().
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	logfile->lf_vp = vp;
4570Sstevel@tonic-gate 	logfile->lf_refcnt = 1;
4580Sstevel@tonic-gate 	mutex_init(&logfile->lf_lock, NULL, MUTEX_DEFAULT, NULL);
4590Sstevel@tonic-gate 	rfsl_log_file++;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
4625331Samw 	error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
4630Sstevel@tonic-gate 	if (error) {
4640Sstevel@tonic-gate 		nfs_cmn_err(error, CE_WARN,
4655112Sbatschul 		    "log_file_create: Can not stat %s - error = %m",  name);
4660Sstevel@tonic-gate 		goto out;
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	if (va.va_size == 0) {
4700Sstevel@tonic-gate 		struct lr_alloc lr;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		/*
4730Sstevel@tonic-gate 		 * Write Header.
4740Sstevel@tonic-gate 		 */
4750Sstevel@tonic-gate 		create_buffer_header(&loghdr, &loghdr_len, &loghdr_free);
4760Sstevel@tonic-gate 		/*
4770Sstevel@tonic-gate 		 * Dummy up a lr_alloc struct for the write
4780Sstevel@tonic-gate 		 */
4790Sstevel@tonic-gate 		lr.next = lr.prev = &lr;
4800Sstevel@tonic-gate 		lr.lr_flags = 0;
4810Sstevel@tonic-gate 		lr.log_record = loghdr;
4820Sstevel@tonic-gate 		lr.size = loghdr_len;
4830Sstevel@tonic-gate 		lr.alloc_cache = NULL;
4840Sstevel@tonic-gate 		lr.exi = NULL;
4850Sstevel@tonic-gate 		lr.lb = NULL;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 		mutex_enter(&logfile->lf_lock);
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		error = nfslog_write_logrecords(logfile, &lr, 1);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 		mutex_exit(&logfile->lf_lock);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		if (error != 0) {
4940Sstevel@tonic-gate 			nfs_cmn_err(error, CE_WARN,
4955112Sbatschul 			    "log_file_create: Can not write header "
4965112Sbatschul 			    "on %s - error = %m", name);
4970Sstevel@tonic-gate 			goto out;
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 	*lfpp = logfile;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if (loghdr != NULL)
5030Sstevel@tonic-gate 		kmem_free(loghdr, loghdr_free);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	return (0);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate out:
5080Sstevel@tonic-gate 	if (vp != NULL) {
5090Sstevel@tonic-gate 		int error1;
5100Sstevel@tonic-gate 		error1 = VOP_CLOSE(vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
5115331Samw 		    CRED(), NULL);
5120Sstevel@tonic-gate 		if (error1) {
5130Sstevel@tonic-gate 			nfs_cmn_err(error1, CE_WARN,
5145112Sbatschul 			    "log_file_create: Can not close %s - "
5155112Sbatschul 			    "error = %m", name);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 		VN_RELE(vp);
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	kmem_free(name, namelen + 1);
5210Sstevel@tonic-gate 	if (logfile != NULL) {
5220Sstevel@tonic-gate 		mutex_destroy(&logfile->lf_lock);
5230Sstevel@tonic-gate 		kmem_free(logfile, sizeof (*logfile));
5240Sstevel@tonic-gate 		rfsl_log_file--;
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 	if (loghdr != NULL)
5270Sstevel@tonic-gate 		kmem_free(loghdr, loghdr_free);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	return (error);
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate  * Release a log_file structure
5340Sstevel@tonic-gate  */
5350Sstevel@tonic-gate static void
log_file_rele(struct log_file * lfp)5360Sstevel@tonic-gate log_file_rele(struct log_file *lfp)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	int len;
5390Sstevel@tonic-gate 	int error;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	mutex_enter(&lfp->lf_lock);
5420Sstevel@tonic-gate 	if (--lfp->lf_refcnt > 0) {
5430Sstevel@tonic-gate 		LOGGING_DPRINT((10,
5445112Sbatschul 		    "log_file_rele lfp=%p decremented refcnt to %d\n",
5457240Srh87107 		    (void *)lfp, lfp->lf_refcnt));
5460Sstevel@tonic-gate 		mutex_exit(&lfp->lf_lock);
5470Sstevel@tonic-gate 		return;
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	if (lfp->lf_refcnt < 0) {
5500Sstevel@tonic-gate 		panic("log_file_rele: log_file refcnt < 0");
5510Sstevel@tonic-gate 		/*NOTREACHED*/
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 
5547240Srh87107 	LOGGING_DPRINT((10, "log_file_rele lfp=%p freeing node\n",
5557240Srh87107 	    (void *)lfp));
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	lfp->lf_flags &= ~(L_PRINTED | L_ERROR);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	ASSERT(lfp->lf_flags == 0);
5600Sstevel@tonic-gate 	ASSERT(lfp->lf_writers == 0);
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	if (error = VOP_CLOSE(lfp->lf_vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
5635331Samw 	    CRED(), NULL)) {
5640Sstevel@tonic-gate 		nfs_cmn_err(error, CE_WARN,
5655112Sbatschul 		    "NFS: Could not close log buffer %s - error = %m",
5665112Sbatschul 		    lfp->lf_path);
5670Sstevel@tonic-gate #ifdef DEBUG
5680Sstevel@tonic-gate 	} else {
5690Sstevel@tonic-gate 		LOGGING_DPRINT((3,
5705112Sbatschul 		    "log_file_rele: %s has been closed vp=%p v_count=%d\n",
5717240Srh87107 		    lfp->lf_path, (void *)lfp->lf_vp, lfp->lf_vp->v_count));
5720Sstevel@tonic-gate #endif
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 	VN_RELE(lfp->lf_vp);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	len = strlen(lfp->lf_path) + 1;
5770Sstevel@tonic-gate 	kmem_free(lfp->lf_path, len);
5780Sstevel@tonic-gate 	kmem_free(lfp, sizeof (*lfp));
5790Sstevel@tonic-gate 	rfsl_log_file--;
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate /*
5830Sstevel@tonic-gate  * Allocates a record of the size specified.
5840Sstevel@tonic-gate  * 'exi' identifies the exportinfo structure being logged.
5850Sstevel@tonic-gate  * 'size' indicates how much memory should be allocated
5860Sstevel@tonic-gate  * 'cookie' is used to store an opaque value for the caller for later use
5870Sstevel@tonic-gate  * 'flags' currently ignored.
5880Sstevel@tonic-gate  *
5890Sstevel@tonic-gate  * Returns a pointer to the beginning of the allocated memory.
5900Sstevel@tonic-gate  * 'cookie' is a pointer to the 'lr_alloc' struct; this will be used
5910Sstevel@tonic-gate  * to keep track of the encoded record and contains all the info
5920Sstevel@tonic-gate  * for enqueuing the record on the log buffer for later writing.
5930Sstevel@tonic-gate  *
5940Sstevel@tonic-gate  * nfslog_record_put() must be used to 'free' this record or allocation.
5950Sstevel@tonic-gate  */
5960Sstevel@tonic-gate /* ARGSUSED */
5970Sstevel@tonic-gate void *
nfslog_record_alloc(struct exportinfo * exi,int alloc_indx,void ** cookie,int flags)5980Sstevel@tonic-gate nfslog_record_alloc(
5990Sstevel@tonic-gate 	struct exportinfo *exi,
6000Sstevel@tonic-gate 	int alloc_indx,
6010Sstevel@tonic-gate 	void **cookie,
6020Sstevel@tonic-gate 	int flags)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate 	struct lr_alloc *lrp;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	lrp = (struct lr_alloc *)
6075112Sbatschul 	    kmem_cache_alloc(nfslog_mem_alloc[alloc_indx].mem_cache,
6085112Sbatschul 	    KM_NOSLEEP);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (lrp == NULL) {
6110Sstevel@tonic-gate 		*cookie = NULL;
6120Sstevel@tonic-gate 		return (NULL);
6130Sstevel@tonic-gate 	}
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	lrp->next = lrp;
6160Sstevel@tonic-gate 	lrp->prev = lrp;
6170Sstevel@tonic-gate 	lrp->lr_flags = 0;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	lrp->log_record = (caddr_t)((uintptr_t)lrp +
6205112Sbatschul 	    (uintptr_t)sizeof (struct lr_alloc));
6210Sstevel@tonic-gate 	lrp->size = nfslog_mem_alloc[alloc_indx].size;
6220Sstevel@tonic-gate 	lrp->alloc_cache = nfslog_mem_alloc[alloc_indx].mem_cache;
6230Sstevel@tonic-gate 	lrp->exi = exi;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (exi->exi_export.ex_flags & EX_LOG) {
6260Sstevel@tonic-gate 		LOG_BUFFER_HOLD(exi->exi_logbuffer);
6270Sstevel@tonic-gate 		lrp->lb = exi->exi_logbuffer;
6280Sstevel@tonic-gate 	} else {
6290Sstevel@tonic-gate 		lrp->lb = NULL;
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	*cookie = (void *)lrp;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	LOGGING_DPRINT((3,
6355112Sbatschul 	    "nfslog_record_alloc(log_buffer=%p mem=%p size=%lu)\n",
6367240Srh87107 	    (void *)exi->exi_logbuffer, (void *)lrp->log_record, lrp->size));
6370Sstevel@tonic-gate 	return (lrp->log_record);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate  * After the above nfslog_record_alloc() has been called and a record
6420Sstevel@tonic-gate  * encoded into the buffer that was returned, this function is called
6430Sstevel@tonic-gate  * to handle appropriate disposition of the newly created record.
6440Sstevel@tonic-gate  * The cookie value is the one that was returned from nfslog_record_alloc().
6450Sstevel@tonic-gate  * Size is the actual size of the record that was encoded.  This is
6460Sstevel@tonic-gate  * passed in because the size used for the alloc was just an approximation.
6470Sstevel@tonic-gate  * The sync parameter is used to tell us if we need to force this record
6480Sstevel@tonic-gate  * to disk and if not it will be queued for later writing.
6490Sstevel@tonic-gate  *
6500Sstevel@tonic-gate  * Note that if the size parameter has a value of 0, then the record is
6510Sstevel@tonic-gate  * not written to the log and the associated data structures are released.
6520Sstevel@tonic-gate  */
6530Sstevel@tonic-gate void
nfslog_record_put(void * cookie,size_t size,bool_t sync,unsigned int which_buffers)6540Sstevel@tonic-gate nfslog_record_put(void *cookie, size_t size, bool_t sync,
6550Sstevel@tonic-gate 	unsigned int which_buffers)
6560Sstevel@tonic-gate {
6570Sstevel@tonic-gate 	struct lr_alloc *lrp = (struct lr_alloc *)cookie;
6580Sstevel@tonic-gate 	struct log_buffer *lbp = lrp->lb;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	/*
6610Sstevel@tonic-gate 	 * If the caller has nothing to write or if there is
6620Sstevel@tonic-gate 	 * an apparent error, rele the buffer and free.
6630Sstevel@tonic-gate 	 */
6640Sstevel@tonic-gate 	if (size == 0 || size > lrp->size) {
6650Sstevel@tonic-gate 		nfslog_free_logrecords(lrp);
6660Sstevel@tonic-gate 		return;
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	/*
6700Sstevel@tonic-gate 	 * Reset the size to what actually needs to be written
6710Sstevel@tonic-gate 	 * This is used later on when the iovec is built for
6720Sstevel@tonic-gate 	 * writing the records to the log file.
6730Sstevel@tonic-gate 	 */
6740Sstevel@tonic-gate 	lrp->size = size;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/* append to all if public exi */
6770Sstevel@tonic-gate 	if (which_buffers == NFSLOG_ALL_BUFFERS) {
6780Sstevel@tonic-gate 		(void) nfslog_record_append2all(lrp);
6790Sstevel@tonic-gate 		nfslog_free_logrecords(lrp);
6800Sstevel@tonic-gate 		return;
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/* Insert the record on the list to be written */
6840Sstevel@tonic-gate 	mutex_enter(&lbp->lb_lock);
6850Sstevel@tonic-gate 	if (lbp->lb_records == NULL) {
6860Sstevel@tonic-gate 		lbp->lb_records = (caddr_t)lrp;
6870Sstevel@tonic-gate 		lbp->lb_num_recs = 1;
6880Sstevel@tonic-gate 		lbp->lb_size_queued = lrp->size;
6890Sstevel@tonic-gate 	} else {
6900Sstevel@tonic-gate 		insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev);
6910Sstevel@tonic-gate 		lbp->lb_num_recs++;
6920Sstevel@tonic-gate 		lbp->lb_size_queued += lrp->size;
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * Determine if the queue for this log buffer should be flushed.
6970Sstevel@tonic-gate 	 * This is done by either the number of records queued, the total
6980Sstevel@tonic-gate 	 * size of all records queued or by the request of the caller
6990Sstevel@tonic-gate 	 * via the sync parameter.
7000Sstevel@tonic-gate 	 */
7010Sstevel@tonic-gate 	if (lbp->lb_size_queued >= nfslog_num_bytes_to_write ||
7025112Sbatschul 	    lbp->lb_num_recs > nfslog_num_records_to_write || sync == TRUE) {
7030Sstevel@tonic-gate 		mutex_exit(&lbp->lb_lock);
7040Sstevel@tonic-gate 		(void) nfslog_records_flush_to_disk(lbp);
7050Sstevel@tonic-gate 	} else {
7060Sstevel@tonic-gate 		mutex_exit(&lbp->lb_lock);
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate  * Examine the log_buffer struct to see if there are queue log records
7130Sstevel@tonic-gate  * that need to be written to disk.  If some exist, pull them off of
7140Sstevel@tonic-gate  * the log buffer and write them to the log file.
7150Sstevel@tonic-gate  */
7160Sstevel@tonic-gate static int
nfslog_records_flush_to_disk(struct log_buffer * lbp)7170Sstevel@tonic-gate nfslog_records_flush_to_disk(struct log_buffer *lbp)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	mutex_enter(&lbp->lb_lock);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	if (lbp->lb_records == NULL) {
7230Sstevel@tonic-gate 		mutex_exit(&lbp->lb_lock);
7240Sstevel@tonic-gate 		return (0);
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 	return	(nfslog_records_flush_to_disk_nolock(lbp));
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate /*
7300Sstevel@tonic-gate  * Function requires that the caller holds lb_lock.
7310Sstevel@tonic-gate  * Function flushes any records in the log buffer to the disk.
7320Sstevel@tonic-gate  * Function drops the lb_lock on return.
7330Sstevel@tonic-gate  */
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate static int
nfslog_records_flush_to_disk_nolock(struct log_buffer * lbp)7360Sstevel@tonic-gate nfslog_records_flush_to_disk_nolock(struct log_buffer *lbp)
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	struct log_file *lfp = NULL;
7390Sstevel@tonic-gate 	struct lr_alloc *lrp_writers;
7400Sstevel@tonic-gate 	int num_recs;
7410Sstevel@tonic-gate 	int error = 0;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&lbp->lb_lock));
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	lfp = lbp->lb_logfile;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	LOG_FILE_LOCK_TO_WRITE(lfp);
7480Sstevel@tonic-gate 	ASSERT(lbp->lb_records != NULL);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	lrp_writers = (struct lr_alloc *)lbp->lb_records;
7510Sstevel@tonic-gate 	lbp->lb_records = NULL;
7520Sstevel@tonic-gate 	num_recs = lbp->lb_num_recs;
7530Sstevel@tonic-gate 	lbp->lb_num_recs = 0;
7540Sstevel@tonic-gate 	lbp->lb_size_queued = 0;
7550Sstevel@tonic-gate 	mutex_exit(&lbp->lb_lock);
7560Sstevel@tonic-gate 	error = nfslog_write_logrecords(lfp, lrp_writers, num_recs);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	LOG_FILE_UNLOCK_FROM_WRITE(lfp);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	nfslog_free_logrecords(lrp_writers);
7610Sstevel@tonic-gate 	return (error);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate /*
7660Sstevel@tonic-gate  * Take care of writing the provided log record(s) to the log file.
7670Sstevel@tonic-gate  * We group the log records with an iovec and use VOP_WRITE to append
7680Sstevel@tonic-gate  * them to the end of the log file.
7690Sstevel@tonic-gate  */
7700Sstevel@tonic-gate static int
nfslog_write_logrecords(struct log_file * lfp,struct lr_alloc * lrp_writers,int num_recs)7710Sstevel@tonic-gate nfslog_write_logrecords(struct log_file *lfp,
7720Sstevel@tonic-gate 	struct lr_alloc *lrp_writers, int num_recs)
7730Sstevel@tonic-gate {
7740Sstevel@tonic-gate 	struct uio uio;
7750Sstevel@tonic-gate 	struct iovec *iovp;
7760Sstevel@tonic-gate 	int size_iovecs;
7770Sstevel@tonic-gate 	vnode_t *vp;
7780Sstevel@tonic-gate 	struct vattr va;
7790Sstevel@tonic-gate 	struct lr_alloc *lrp;
7800Sstevel@tonic-gate 	int i;
7810Sstevel@tonic-gate 	ssize_t len;
7820Sstevel@tonic-gate 	int ioflag = FAPPEND;
7830Sstevel@tonic-gate 	int error = 0;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&lfp->lf_lock));
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	vp = lfp->lf_vp;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	size_iovecs = sizeof (struct iovec) * num_recs;
7900Sstevel@tonic-gate 	iovp = (struct iovec *)kmem_alloc(size_iovecs, KM_NOSLEEP);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	if (iovp == NULL) {
7930Sstevel@tonic-gate 		error = ENOMEM;
7940Sstevel@tonic-gate 		goto out;
7950Sstevel@tonic-gate 	}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	/* Build the iovec based on the list of log records */
7980Sstevel@tonic-gate 	i = 0;
7990Sstevel@tonic-gate 	len = 0;
8000Sstevel@tonic-gate 	lrp = lrp_writers;
8010Sstevel@tonic-gate 	do {
8020Sstevel@tonic-gate 		iovp[i].iov_base = lrp->log_record;
8030Sstevel@tonic-gate 		iovp[i].iov_len = lrp->size;
8040Sstevel@tonic-gate 		len += lrp->size;
8050Sstevel@tonic-gate 		lrp = lrp->next;
8060Sstevel@tonic-gate 		i++;
8070Sstevel@tonic-gate 	} while (lrp != lrp_writers);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	ASSERT(i == num_recs);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	uio.uio_iov = iovp;
8120Sstevel@tonic-gate 	uio.uio_iovcnt = num_recs;
8130Sstevel@tonic-gate 	uio.uio_loffset = 0;
8140Sstevel@tonic-gate 	uio.uio_segflg = (short)UIO_SYSSPACE;
8150Sstevel@tonic-gate 	uio.uio_resid = len;
8160Sstevel@tonic-gate 	uio.uio_llimit = (rlim64_t)MAXOFFSET_T;
8170Sstevel@tonic-gate 	uio.uio_fmode = FWRITE;
8180Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_DEFAULT;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Save the size. If the write fails, reset the size to avoid
8220Sstevel@tonic-gate 	 * corrupted log buffer files.
8230Sstevel@tonic-gate 	 */
8240Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);  /* UIO_WRITE */
8275331Samw 	if ((error = VOP_GETATTR(vp, &va, 0, CRED(), NULL)) == 0) {
8280Sstevel@tonic-gate 		if ((len + va.va_size) < (MAXOFF32_T)) {
8290Sstevel@tonic-gate 			error = VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
8302707Spf199842 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
8310Sstevel@tonic-gate 			if (uio.uio_resid)
8320Sstevel@tonic-gate 				error = ENOSPC;
8330Sstevel@tonic-gate 			if (error)
8340Sstevel@tonic-gate 				(void) VOP_SETATTR(vp, &va, 0, CRED(), NULL);
8350Sstevel@tonic-gate 		} else {
8362707Spf199842 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
8370Sstevel@tonic-gate 			if (!(lfp->lf_flags & L_PRINTED)) {
8380Sstevel@tonic-gate 				cmn_err(CE_WARN,
8390Sstevel@tonic-gate 				    "NFS Logging: buffer file %s exceeds 2GB; "
8400Sstevel@tonic-gate 				    "stopped writing buffer \n", lfp->lf_path);
8410Sstevel@tonic-gate 			}
8420Sstevel@tonic-gate 			error = ENOSPC;
8430Sstevel@tonic-gate 		}
8442707Spf199842 	} else {
8452707Spf199842 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
8460Sstevel@tonic-gate 	}
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	kmem_free(iovp, size_iovecs);
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate out:
8510Sstevel@tonic-gate 	if (error) {
8520Sstevel@tonic-gate 		if (!(lfp->lf_flags & L_PRINTED)) {
8530Sstevel@tonic-gate 			nfs_cmn_err(error, CE_WARN,
8545112Sbatschul 			    "NFS Logging disabled for buffer %s - "
8555112Sbatschul 			    "write error = %m\n", lfp->lf_path);
8560Sstevel@tonic-gate 			lfp->lf_flags |= L_PRINTED;
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 	} else if (lfp->lf_flags & (L_ERROR | L_PRINTED)) {
8590Sstevel@tonic-gate 		lfp->lf_flags &= ~(L_ERROR | L_PRINTED);
8600Sstevel@tonic-gate 		cmn_err(CE_WARN,
8615112Sbatschul 		    "NFS Logging re-enabled for buffer %s\n", lfp->lf_path);
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	return (error);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate static void
nfslog_free_logrecords(struct lr_alloc * lrp_writers)8680Sstevel@tonic-gate nfslog_free_logrecords(struct lr_alloc *lrp_writers)
8690Sstevel@tonic-gate {
8700Sstevel@tonic-gate 	struct lr_alloc *lrp = lrp_writers;
8710Sstevel@tonic-gate 	struct lr_alloc *lrp_free;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	do {
8740Sstevel@tonic-gate 		lrp_free = lrp;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 		lrp = lrp->next;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 		/*
8790Sstevel@tonic-gate 		 * Check to see if we are supposed to free this structure
8800Sstevel@tonic-gate 		 * and relese the log_buffer ref count.
8810Sstevel@tonic-gate 		 * It may be the case that the caller does not want this
8820Sstevel@tonic-gate 		 * structure and its record contents freed just yet.
8830Sstevel@tonic-gate 		 */
8840Sstevel@tonic-gate 		if ((lrp_free->lr_flags & LR_ALLOC_NOFREE) == 0) {
8850Sstevel@tonic-gate 			if (lrp_free->lb != NULL)
8860Sstevel@tonic-gate 				log_buffer_rele(lrp_free->lb);
8870Sstevel@tonic-gate 			if (lrp_free->alloc_cache) /* double check */
8880Sstevel@tonic-gate 				kmem_cache_free(lrp_free->alloc_cache,
8895112Sbatschul 				    (void *)lrp_free);
8900Sstevel@tonic-gate 		} else {
8910Sstevel@tonic-gate 			/*
8920Sstevel@tonic-gate 			 * after being pulled from the list the
8930Sstevel@tonic-gate 			 * pointers need to be reinitialized.
8940Sstevel@tonic-gate 			 */
8950Sstevel@tonic-gate 			lrp_free->next = lrp_free;
8960Sstevel@tonic-gate 			lrp_free->prev = lrp_free;
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	} while (lrp != lrp_writers);
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate /*
9030Sstevel@tonic-gate  * Rename lbp->lb_logfile to reflect the true name requested by 'share'
9040Sstevel@tonic-gate  */
9050Sstevel@tonic-gate static int
nfslog_logbuffer_rename(struct log_buffer * lbp)9060Sstevel@tonic-gate nfslog_logbuffer_rename(struct log_buffer *lbp)
9070Sstevel@tonic-gate {
9080Sstevel@tonic-gate 	struct log_file *lf;
9090Sstevel@tonic-gate 	int error;
9100Sstevel@tonic-gate 	struct log_file *logfile;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	/*
9130Sstevel@tonic-gate 	 * Try our best to get the cache records into the log file
9140Sstevel@tonic-gate 	 * before the rename occurs.
9150Sstevel@tonic-gate 	 */
9160Sstevel@tonic-gate 	(void) nfslog_records_flush_to_disk(lbp);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	/*
9190Sstevel@tonic-gate 	 * Hold lb_lock before retrieving
9200Sstevel@tonic-gate 	 * lb_logfile.
9210Sstevel@tonic-gate 	 * Hold a reference to the
9220Sstevel@tonic-gate 	 * "lf" structure. this is
9230Sstevel@tonic-gate 	 * same as LOG_FILE_HOLD()
9240Sstevel@tonic-gate 	 */
9250Sstevel@tonic-gate 	mutex_enter(&(lbp)->lb_lock);
9260Sstevel@tonic-gate 	lf = lbp->lb_logfile;
9270Sstevel@tonic-gate 	mutex_enter(&(lf)->lf_lock);
9280Sstevel@tonic-gate 	mutex_exit(&(lbp)->lb_lock);
9290Sstevel@tonic-gate 	lf->lf_refcnt++;
9300Sstevel@tonic-gate 	mutex_exit(&(lf)->lf_lock);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	LOGGING_DPRINT((10, "nfslog_logbuffer_rename: renaming %s to %s\n",
9335112Sbatschul 	    lf->lf_path, lbp->lb_path));
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/*
9360Sstevel@tonic-gate 	 * rename the current buffer to what the daemon expects
9370Sstevel@tonic-gate 	 */
9380Sstevel@tonic-gate 	if (error = nfslog_logfile_rename(lf->lf_path, lbp->lb_path))
9390Sstevel@tonic-gate 		goto out;
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/*
9420Sstevel@tonic-gate 	 * Create a new working buffer file and have all new data sent there.
9430Sstevel@tonic-gate 	 */
9440Sstevel@tonic-gate 	if (error = log_file_create(lbp->lb_path, &logfile)) {
9450Sstevel@tonic-gate 		/* Attempt to rename to original */
9460Sstevel@tonic-gate 		(void) nfslog_logfile_rename(lbp->lb_path, lf->lf_path);
9470Sstevel@tonic-gate 		goto out;
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * Hold the lb_lock here, this will make
9520Sstevel@tonic-gate 	 * all the threads trying to access lb->logfile block
9530Sstevel@tonic-gate 	 * and get a new logfile structure instead of old one.
9540Sstevel@tonic-gate 	 */
9550Sstevel@tonic-gate 	mutex_enter(&(lbp)->lb_lock);
9560Sstevel@tonic-gate 	lbp->lb_logfile = logfile;
9570Sstevel@tonic-gate 	mutex_exit(&(lbp)->lb_lock);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	LOG_FILE_RELE(lf);	/* release log_buffer's reference */
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	/*
9620Sstevel@tonic-gate 	 * Wait for log_file to be in a quiescent state before we
9630Sstevel@tonic-gate 	 * return to our caller to let it proceed with the reading of
9640Sstevel@tonic-gate 	 * this file.
9650Sstevel@tonic-gate 	 */
9660Sstevel@tonic-gate 	nfslog_logfile_wait(lf);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate out:
9690Sstevel@tonic-gate 	/*
9700Sstevel@tonic-gate 	 * Release our reference on "lf" in two different cases.
9710Sstevel@tonic-gate 	 * 1. Error condition, release only the reference
9720Sstevel@tonic-gate 	 *    that we held at the begining of this
9730Sstevel@tonic-gate 	 *    routine on "lf" structure.
9740Sstevel@tonic-gate 	 * 2. Fall through condition, no errors but the old
9750Sstevel@tonic-gate 	 *    logfile structure "lf" has been replaced with
9760Sstevel@tonic-gate 	 *    the new "logfile" structure, so release the
9770Sstevel@tonic-gate 	 *    reference that was part of the creation of
9780Sstevel@tonic-gate 	 *    "lf" structure to free up the resources.
9790Sstevel@tonic-gate 	 */
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	LOG_FILE_RELE(lf);
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	return (error);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * Renames the 'from' file to 'new'.
9880Sstevel@tonic-gate  */
9890Sstevel@tonic-gate static int
nfslog_logfile_rename(char * from,char * new)9900Sstevel@tonic-gate nfslog_logfile_rename(char *from, char *new)
9910Sstevel@tonic-gate {
9920Sstevel@tonic-gate 	int error;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	if (error = vn_rename(from, new, UIO_SYSSPACE)) {
9950Sstevel@tonic-gate 		cmn_err(CE_WARN,
9965112Sbatschul 		    "nfslog_logfile_rename: couldn't rename %s to %s\n",
9975112Sbatschul 		    from, new);
9980Sstevel@tonic-gate 	}
9990Sstevel@tonic-gate 	return (error);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate  * Wait for the log_file writers to finish before returning
10040Sstevel@tonic-gate  */
10050Sstevel@tonic-gate static void
nfslog_logfile_wait(struct log_file * lf)10060Sstevel@tonic-gate nfslog_logfile_wait(struct log_file *lf)
10070Sstevel@tonic-gate {
10080Sstevel@tonic-gate 	mutex_enter(&lf->lf_lock);
10090Sstevel@tonic-gate 	while (lf->lf_writers > 0) {
10100Sstevel@tonic-gate 		lf->lf_flags |= L_WAITING;
10110Sstevel@tonic-gate 		(void) cv_wait_sig(&lf->lf_cv_waiters, &lf->lf_lock);
10120Sstevel@tonic-gate 	}
10130Sstevel@tonic-gate 	mutex_exit(&lf->lf_lock);
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate static int
nfslog_record_append2all(struct lr_alloc * lrp)10170Sstevel@tonic-gate nfslog_record_append2all(struct lr_alloc *lrp)
10180Sstevel@tonic-gate {
10190Sstevel@tonic-gate 	struct log_buffer *lbp, *nlbp;
10200Sstevel@tonic-gate 	int error, ret_error = 0;
10210Sstevel@tonic-gate 	int lr_flags = lrp->lr_flags;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	rw_enter(&nfslog_buffer_list_lock, RW_READER);
10240Sstevel@tonic-gate 	if ((lbp = nfslog_buffer_list) != NULL)
10250Sstevel@tonic-gate 		LOG_BUFFER_HOLD(lbp);
10260Sstevel@tonic-gate 	for (nlbp = NULL; lbp != NULL; lbp = nlbp) {
10270Sstevel@tonic-gate 		if ((nlbp = lbp->lb_next) != NULL) {
10280Sstevel@tonic-gate 			/*
10290Sstevel@tonic-gate 			 * Remember next element in the list
10300Sstevel@tonic-gate 			 */
10310Sstevel@tonic-gate 			LOG_BUFFER_HOLD(nlbp);
10320Sstevel@tonic-gate 		}
10330Sstevel@tonic-gate 		rw_exit(&nfslog_buffer_list_lock);
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 		/*
10360Sstevel@tonic-gate 		 * Insert the record on the buffer's list to be written
10370Sstevel@tonic-gate 		 * and then flush the records to the log file.
10380Sstevel@tonic-gate 		 * Make sure to set the no free flag so that the
10390Sstevel@tonic-gate 		 * record can be used for the next write
10400Sstevel@tonic-gate 		 */
10410Sstevel@tonic-gate 		lrp->lr_flags = LR_ALLOC_NOFREE;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 		ASSERT(lbp != NULL);
10440Sstevel@tonic-gate 		mutex_enter(&lbp->lb_lock);
10450Sstevel@tonic-gate 		if (lbp->lb_records == NULL) {
10460Sstevel@tonic-gate 			lbp->lb_records = (caddr_t)lrp;
10470Sstevel@tonic-gate 			lbp->lb_num_recs = 1;
10480Sstevel@tonic-gate 			lbp->lb_size_queued = lrp->size;
10490Sstevel@tonic-gate 		} else {
10500Sstevel@tonic-gate 			insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev);
10510Sstevel@tonic-gate 			lbp->lb_num_recs++;
10520Sstevel@tonic-gate 			lbp->lb_size_queued += lrp->size;
10530Sstevel@tonic-gate 		}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		/*
10560Sstevel@tonic-gate 		 * Flush log records to disk.
10570Sstevel@tonic-gate 		 * Function is called with lb_lock held.
10580Sstevel@tonic-gate 		 * Function drops the lb_lock on return.
10590Sstevel@tonic-gate 		 */
10600Sstevel@tonic-gate 		error = nfslog_records_flush_to_disk_nolock(lbp);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		if (error) {
10630Sstevel@tonic-gate 			ret_error = -1;
10640Sstevel@tonic-gate 			nfs_cmn_err(error, CE_WARN,
10655112Sbatschul 			    "rfsl_log_pubfh: could not append record to "
10665112Sbatschul 			    "\"%s\" error = %m\n", lbp->lb_path);
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 		log_buffer_rele(lbp);
10690Sstevel@tonic-gate 		rw_enter(&nfslog_buffer_list_lock, RW_READER);
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 	rw_exit(&nfslog_buffer_list_lock);
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	lrp->lr_flags = lr_flags;
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	return (ret_error);
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate #ifdef DEBUG
10790Sstevel@tonic-gate static int logging_debug = 0;
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate /*
10820Sstevel@tonic-gate  * 0) no debugging
10830Sstevel@tonic-gate  * 3) current test software
10840Sstevel@tonic-gate  * 10) random stuff
10850Sstevel@tonic-gate  */
10860Sstevel@tonic-gate void
nfslog_dprint(const int level,const char * fmt,...)10870Sstevel@tonic-gate nfslog_dprint(const int level, const char *fmt, ...)
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate 	va_list args;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	if (logging_debug == level ||
10920Sstevel@tonic-gate 	    (logging_debug > 10 && (logging_debug - 10) >= level)) {
10930Sstevel@tonic-gate 		va_start(args, fmt);
10940Sstevel@tonic-gate 		(void) vprintf(fmt, args);
10950Sstevel@tonic-gate 		va_end(args);
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate }
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate #endif /* DEBUG */
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate /*
11020Sstevel@tonic-gate  * NFS Log Flush system call
11030Sstevel@tonic-gate  * Caller must check privileges.
11040Sstevel@tonic-gate  */
11050Sstevel@tonic-gate /* ARGSUSED */
11060Sstevel@tonic-gate int
nfsl_flush(struct nfsl_flush_args * args,model_t model)11070Sstevel@tonic-gate nfsl_flush(struct nfsl_flush_args *args, model_t model)
11080Sstevel@tonic-gate {
11090Sstevel@tonic-gate 	struct flush_thread_params *tparams;
11100Sstevel@tonic-gate 	struct nfsl_flush_args *nfsl_args;
11110Sstevel@tonic-gate 	int error = 0;
11120Sstevel@tonic-gate 	ulong_t buffer_len;
11130Sstevel@tonic-gate 	STRUCT_HANDLE(nfsl_flush_args, uap);
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	STRUCT_SET_HANDLE(uap, model, args);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	tparams = (struct flush_thread_params *)
11185112Sbatschul 	    kmem_zalloc(sizeof (*tparams), KM_SLEEP);
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	nfsl_args = &tparams->tp_args;
11210Sstevel@tonic-gate 	nfsl_args->version =  STRUCT_FGET(uap, version);
11220Sstevel@tonic-gate 	if (nfsl_args->version != NFSL_FLUSH_ARGS_VERS) {
11230Sstevel@tonic-gate 		cmn_err(CE_WARN, "nfsl_flush: exected version %d, got %d",
11245112Sbatschul 		    NFSL_FLUSH_ARGS_VERS, nfsl_args->version);
11250Sstevel@tonic-gate 		return (EIO);
11260Sstevel@tonic-gate 	}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	nfsl_args->directive = STRUCT_FGET(uap, directive);
11290Sstevel@tonic-gate 	if ((nfsl_args->directive & NFSL_ALL) == 0) {
11300Sstevel@tonic-gate 		/*
11310Sstevel@tonic-gate 		 * Process a specific buffer
11320Sstevel@tonic-gate 		 */
11330Sstevel@tonic-gate 		nfsl_args->buff_len = STRUCT_FGET(uap, buff_len);
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 		nfsl_args->buff = (char *)
11365112Sbatschul 		    kmem_alloc(nfsl_args->buff_len, KM_NOSLEEP);
11370Sstevel@tonic-gate 		if (nfsl_args->buff == NULL)
11380Sstevel@tonic-gate 			return (ENOMEM);
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 		error = copyinstr((const char *)STRUCT_FGETP(uap, buff),
11415112Sbatschul 		    nfsl_args->buff, nfsl_args->buff_len, &buffer_len);
11420Sstevel@tonic-gate 		if (error)
11430Sstevel@tonic-gate 			return (EFAULT);
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 		if (nfsl_args->buff_len != buffer_len)
11460Sstevel@tonic-gate 			return (EFAULT);
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	LOGGING_DPRINT((10, "nfsl_flush: Flushing %s buffer(s)\n",
11505112Sbatschul 	    nfsl_args->directive & NFSL_ALL ? "all" : nfsl_args->buff));
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	if (nfsl_args->directive & NFSL_SYNC) {
11530Sstevel@tonic-gate 		/*
11540Sstevel@tonic-gate 		 * Do the work synchronously
11550Sstevel@tonic-gate 		 */
11560Sstevel@tonic-gate 		nfslog_do_flush(tparams);
11570Sstevel@tonic-gate 		error = tparams->tp_error;
11580Sstevel@tonic-gate 		kmem_free(nfsl_args->buff, nfsl_args->buff_len);
11590Sstevel@tonic-gate 		kmem_free(tparams, sizeof (*tparams));
11600Sstevel@tonic-gate 	} else {
11610Sstevel@tonic-gate 		/*
11620Sstevel@tonic-gate 		 * Do the work asynchronously
11630Sstevel@tonic-gate 		 */
11640Sstevel@tonic-gate 		(void) thread_create(NULL, 0, nfslog_do_flush,
11650Sstevel@tonic-gate 		    tparams, 0, &p0, TS_RUN, minclsyspri);
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	return (error);
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate  * This is where buffer flushing would occur, but there is no buffering
11730Sstevel@tonic-gate  * at this time.
11740Sstevel@tonic-gate  * Possibly rename the log buffer for processing.
11755331Samw  * Sets tparams->ta_error equal to the value of the error that occurred,
11760Sstevel@tonic-gate  * 0 otherwise.
11770Sstevel@tonic-gate  * Returns ENOENT if the buffer is not found.
11780Sstevel@tonic-gate  */
11790Sstevel@tonic-gate static void
nfslog_do_flush(struct flush_thread_params * tparams)11800Sstevel@tonic-gate nfslog_do_flush(struct flush_thread_params *tparams)
11810Sstevel@tonic-gate {
11820Sstevel@tonic-gate 	struct nfsl_flush_args *args;
11835112Sbatschul 	struct log_buffer *lbp, *nlbp;
11840Sstevel@tonic-gate 	int error = ENOENT;
11850Sstevel@tonic-gate 	int found = 0;
11860Sstevel@tonic-gate 	char *buf_inprog;	/* name of buff in progress */
11870Sstevel@tonic-gate 	int buf_inprog_len;
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	/*
11900Sstevel@tonic-gate 	 * Sanity check on the arguments.
11910Sstevel@tonic-gate 	 */
11920Sstevel@tonic-gate 	if (!tparams)
11930Sstevel@tonic-gate 		return;
11940Sstevel@tonic-gate 	args = &tparams->tp_args;
11950Sstevel@tonic-gate 	if (!args)
11960Sstevel@tonic-gate 		return;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	rw_enter(&nfslog_buffer_list_lock, RW_READER);
11995112Sbatschul 	if ((lbp = nfslog_buffer_list) != NULL) {
12005112Sbatschul 		LOG_BUFFER_HOLD(lbp);
12015112Sbatschul 	}
12025112Sbatschul 	for (nlbp = NULL; lbp != NULL; lbp = nlbp) {
12035112Sbatschul 		if ((nlbp = lbp->lb_next) != NULL) {
12045112Sbatschul 			LOG_BUFFER_HOLD(nlbp);
12055112Sbatschul 		}
12065112Sbatschul 		rw_exit(&nfslog_buffer_list_lock);
12070Sstevel@tonic-gate 		if (args->directive & NFSL_ALL) {
12080Sstevel@tonic-gate 			(void) nfslog_records_flush_to_disk(lbp);
12090Sstevel@tonic-gate 		} else {
12100Sstevel@tonic-gate 			if ((strcmp(lbp->lb_path, args->buff) == 0) &&
12115112Sbatschul 			    (args->directive & NFSL_RENAME)) {
12120Sstevel@tonic-gate 				error = nfslog_logbuffer_rename(lbp);
12130Sstevel@tonic-gate 				found++;
12145112Sbatschul 				if (nlbp != NULL)
12155112Sbatschul 					log_buffer_rele(nlbp);
12165112Sbatschul 				log_buffer_rele(lbp);
12170Sstevel@tonic-gate 				break;
12180Sstevel@tonic-gate 			}
12190Sstevel@tonic-gate 		}
12205112Sbatschul 		log_buffer_rele(lbp);
12215112Sbatschul 		rw_enter(&nfslog_buffer_list_lock, RW_READER);
12220Sstevel@tonic-gate 	}
12235112Sbatschul 	if (!found)
12245112Sbatschul 		rw_exit(&nfslog_buffer_list_lock);
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	if (!found && ((args->directive & NFSL_ALL) == 0) &&
12270Sstevel@tonic-gate 	    (args->directive & NFSL_RENAME)) {
12280Sstevel@tonic-gate 		/*
12290Sstevel@tonic-gate 		 * The specified buffer is not currently in use,
12300Sstevel@tonic-gate 		 * simply rename the file indicated.
12310Sstevel@tonic-gate 		 */
12320Sstevel@tonic-gate 		buf_inprog_len = strlen(args->buff) +
12335112Sbatschul 		    strlen(LOG_INPROG_STRING) + 1;
12340Sstevel@tonic-gate 		buf_inprog = (caddr_t)kmem_alloc(buf_inprog_len, KM_SLEEP);
12350Sstevel@tonic-gate 		(void) sprintf(buf_inprog, "%s%s",
12365112Sbatschul 		    args->buff, LOG_INPROG_STRING);
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 		error = nfslog_logfile_rename(buf_inprog, args->buff);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 		kmem_free(buf_inprog, buf_inprog_len);
12410Sstevel@tonic-gate 	}
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate out:
12440Sstevel@tonic-gate 	if ((args->directive & NFSL_SYNC) == 0) {
12450Sstevel@tonic-gate 		/*
12460Sstevel@tonic-gate 		 * Work was performed asynchronously, the caller is
12470Sstevel@tonic-gate 		 * no longer waiting for us.
12480Sstevel@tonic-gate 		 * Free the thread arguments and exit.
12490Sstevel@tonic-gate 		 */
12500Sstevel@tonic-gate 		kmem_free(args->buff, args->buff_len);
12510Sstevel@tonic-gate 		kmem_free(tparams, sizeof (*tparams));
12520Sstevel@tonic-gate 		thread_exit();
12530Sstevel@tonic-gate 		/* NOTREACHED */
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	tparams->tp_error = error;
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate /*
12600Sstevel@tonic-gate  * Generate buffer_header.
12610Sstevel@tonic-gate  * 'loghdr' points the the buffer_header, and *reclen
12620Sstevel@tonic-gate  * contains the length of the buffer.
12630Sstevel@tonic-gate  */
12640Sstevel@tonic-gate static void
create_buffer_header(caddr_t * loghdr,size_t * reclen,size_t * freesize)12650Sstevel@tonic-gate create_buffer_header(caddr_t *loghdr, size_t *reclen, size_t *freesize)
12660Sstevel@tonic-gate {
12670Sstevel@tonic-gate 	timestruc_t		now;
12680Sstevel@tonic-gate 	nfslog_buffer_header	lh;
12690Sstevel@tonic-gate 	XDR			xdrs;
12700Sstevel@tonic-gate 	unsigned int		final_size;
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	/* pick some size that will hold the buffer_header */
12740Sstevel@tonic-gate 	*freesize = NFSLOG_SMALL_RECORD_SIZE;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	/*
12770Sstevel@tonic-gate 	 * Fill header
12780Sstevel@tonic-gate 	 */
12790Sstevel@tonic-gate 	lh.bh_length = 0;	/* don't know yet how large it will be */
12800Sstevel@tonic-gate 	lh.bh_version = NFSLOG_BUF_VERSION;
12810Sstevel@tonic-gate 	lh.bh_flags = 0;
12820Sstevel@tonic-gate 	lh.bh_offset = 0;
12830Sstevel@tonic-gate 	gethrestime(&now);
12840Sstevel@tonic-gate 	TIMESPEC_TO_TIMESPEC32(&lh.bh_timestamp, &now);
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	/*
12870Sstevel@tonic-gate 	 * Encode the header
12880Sstevel@tonic-gate 	 */
12890Sstevel@tonic-gate 	*loghdr = (caddr_t)kmem_alloc(*freesize, KM_SLEEP);
12900Sstevel@tonic-gate 	xdrmem_create(&xdrs, *loghdr, *freesize, XDR_ENCODE);
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	(void) xdr_nfslog_buffer_header(&xdrs, &lh);
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	/*
12950Sstevel@tonic-gate 	 * Reset with final size of the encoded data
12960Sstevel@tonic-gate 	 */
12970Sstevel@tonic-gate 	final_size = xdr_getpos(&xdrs);
12980Sstevel@tonic-gate 	xdr_setpos(&xdrs, 0);
12990Sstevel@tonic-gate 	(void) xdr_u_int(&xdrs, &final_size);
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	*reclen = (size_t)final_size;
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate /*
13050Sstevel@tonic-gate  * ****************************************************************
13060Sstevel@tonic-gate  * RPC dispatch table for logging
13070Sstevel@tonic-gate  * Indexed by program, version, proc
13080Sstevel@tonic-gate  * Based on NFS dispatch table.
13090Sstevel@tonic-gate  */
13100Sstevel@tonic-gate struct nfslog_proc_disp {
13110Sstevel@tonic-gate 	bool_t	(*xdrargs)();
13120Sstevel@tonic-gate 	bool_t	(*xdrres)();
13130Sstevel@tonic-gate 	bool_t	affects_transactions;	/* Operation affects transaction */
13140Sstevel@tonic-gate 					/* processing */
13150Sstevel@tonic-gate };
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate struct nfslog_vers_disp {
13180Sstevel@tonic-gate 	int	nfslog_dis_nprocs;			/* number of procs */
13190Sstevel@tonic-gate 	struct nfslog_proc_disp	*nfslog_dis_proc_table;	/* proc array */
13200Sstevel@tonic-gate };
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate struct nfslog_prog_disp {
13230Sstevel@tonic-gate 	int	nfslog_dis_prog;		/* program number */
13240Sstevel@tonic-gate 	int	nfslog_dis_versmin;		/* Minimum version value */
13250Sstevel@tonic-gate 	int	nfslog_dis_nvers;		/* Number of version values */
13260Sstevel@tonic-gate 	struct nfslog_vers_disp	*nfslog_dis_vers_table;	/* versions array */
13270Sstevel@tonic-gate };
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate static int rfs_log_bad = 0;	/* incremented on bad log attempts */
13300Sstevel@tonic-gate static int rfs_log_good = 0;	/* incremented on successful log attempts */
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate /*
13330Sstevel@tonic-gate  * Define the actions taken per prog/vers/proc:
13340Sstevel@tonic-gate  *
13350Sstevel@tonic-gate  * In some cases, the nl types are the same as the nfs types and a simple
13360Sstevel@tonic-gate  * bcopy should suffice. Rather that define tens of identical procedures,
13370Sstevel@tonic-gate  * simply define these to bcopy. Similarly this takes care of different
13380Sstevel@tonic-gate  * procs that use same parameter struct.
13390Sstevel@tonic-gate  */
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate static struct nfslog_proc_disp nfslog_proc_v2[] = {
13420Sstevel@tonic-gate 	/*
13430Sstevel@tonic-gate 	 * NFS VERSION 2
13440Sstevel@tonic-gate 	 */
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	/* RFS_NULL = 0 */
13470Sstevel@tonic-gate 	{xdr_void, xdr_void, FALSE},
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	/* RFS_GETATTR = 1 */
13500Sstevel@tonic-gate 	{xdr_fhandle, xdr_nfslog_getattrres, FALSE},
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	/* RFS_SETATTR = 2 */
13530Sstevel@tonic-gate 	{xdr_nfslog_setattrargs, xdr_nfsstat, TRUE},
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
13560Sstevel@tonic-gate 	{xdr_void, xdr_void, FALSE},
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	/* RFS_LOOKUP = 4 */
13590Sstevel@tonic-gate 	{xdr_nfslog_diropargs, xdr_nfslog_diropres, TRUE},
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	/* RFS_READLINK = 5 */
13620Sstevel@tonic-gate 	{xdr_fhandle, xdr_nfslog_rdlnres, FALSE},
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	/* RFS_READ = 6 */
13650Sstevel@tonic-gate 	{xdr_nfslog_nfsreadargs, xdr_nfslog_rdresult, TRUE},
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
13680Sstevel@tonic-gate 	{xdr_void, xdr_void, FALSE},
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	/* RFS_WRITE = 8 */
13710Sstevel@tonic-gate 	{xdr_nfslog_writeargs, xdr_nfslog_writeresult, TRUE},
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 	/* RFS_CREATE = 9 */
13740Sstevel@tonic-gate 	{xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE},
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/* RFS_REMOVE = 10 */
13770Sstevel@tonic-gate 	{xdr_nfslog_diropargs, xdr_nfsstat, TRUE},
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/* RFS_RENAME = 11 */
13800Sstevel@tonic-gate 	{xdr_nfslog_rnmargs, xdr_nfsstat, TRUE},
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	/* RFS_LINK = 12 */
13830Sstevel@tonic-gate 	{xdr_nfslog_linkargs, xdr_nfsstat, TRUE},
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	/* RFS_SYMLINK = 13 */
13860Sstevel@tonic-gate 	{xdr_nfslog_symlinkargs, xdr_nfsstat, TRUE},
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	/* RFS_MKDIR = 14 */
13890Sstevel@tonic-gate 	{xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE},
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	/* RFS_RMDIR = 15 */
13920Sstevel@tonic-gate 	{xdr_nfslog_diropargs, xdr_nfsstat, TRUE},
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 	/* RFS_READDIR = 16 */
13950Sstevel@tonic-gate 	{xdr_nfslog_rddirargs, xdr_nfslog_rddirres, TRUE},
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 	/* RFS_STATFS = 17 */
13980Sstevel@tonic-gate 	{xdr_fhandle, xdr_nfslog_statfs, FALSE},
13990Sstevel@tonic-gate };
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate /*
14030Sstevel@tonic-gate  * NFS VERSION 3
14040Sstevel@tonic-gate  */
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate static struct nfslog_proc_disp nfslog_proc_v3[] = {
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	/* NFSPROC3_NULL = 0 */
14090Sstevel@tonic-gate 	{xdr_void, xdr_void, FALSE},
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	/* NFSPROC3_GETATTR = 1 */
14121610Sthurlow 	{xdr_nfslog_nfs_fh3, xdr_nfslog_GETATTR3res, FALSE},
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	/* NFSPROC3_SETATTR = 2 */
14150Sstevel@tonic-gate 	{xdr_nfslog_SETATTR3args, xdr_nfslog_SETATTR3res, TRUE},
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	/* NFSPROC3_LOOKUP = 3 */
14180Sstevel@tonic-gate 	{xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE},
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/* NFSPROC3_ACCESS = 4 */
14210Sstevel@tonic-gate 	{xdr_nfslog_ACCESS3args, xdr_nfslog_ACCESS3res, FALSE},
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	/* NFSPROC3_READLINK = 5 */
14241610Sthurlow 	{xdr_nfslog_nfs_fh3, xdr_nfslog_READLINK3res, FALSE},
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	/* NFSPROC3_READ = 6 */
14270Sstevel@tonic-gate 	{xdr_nfslog_READ3args, xdr_nfslog_READ3res, TRUE},
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	/* NFSPROC3_WRITE = 7 */
14300Sstevel@tonic-gate 	{xdr_nfslog_WRITE3args, xdr_nfslog_WRITE3res, TRUE},
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 	/* NFSPROC3_CREATE = 8 */
14330Sstevel@tonic-gate 	{xdr_nfslog_CREATE3args, xdr_nfslog_CREATE3res, TRUE},
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	/* NFSPROC3_MKDIR = 9 */
14360Sstevel@tonic-gate 	{xdr_nfslog_MKDIR3args, xdr_nfslog_MKDIR3res, TRUE},
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	/* NFSPROC3_SYMLINK = 10 */
14390Sstevel@tonic-gate 	{xdr_nfslog_SYMLINK3args, xdr_nfslog_SYMLINK3res, TRUE},
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 	/* NFSPROC3_MKNOD = 11 */
14420Sstevel@tonic-gate 	{xdr_nfslog_MKNOD3args, xdr_nfslog_MKNOD3res, TRUE},
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	/* NFSPROC3_REMOVE = 12 */
14450Sstevel@tonic-gate 	{xdr_nfslog_REMOVE3args, xdr_nfslog_REMOVE3res, TRUE},
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	/* NFSPROC3_RMDIR = 13 */
14480Sstevel@tonic-gate 	{xdr_nfslog_RMDIR3args, xdr_nfslog_RMDIR3res, TRUE},
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	/* NFSPROC3_RENAME = 14 */
14510Sstevel@tonic-gate 	{xdr_nfslog_RENAME3args, xdr_nfslog_RENAME3res, TRUE},
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	/* NFSPROC3_LINK = 15 */
14540Sstevel@tonic-gate 	{xdr_nfslog_LINK3args, xdr_nfslog_LINK3res, TRUE},
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	/* NFSPROC3_READDIR = 16 */
14570Sstevel@tonic-gate 	{xdr_nfslog_READDIR3args, xdr_nfslog_READDIR3res, TRUE},
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	/* NFSPROC3_READDIRPLUS = 17 */
14600Sstevel@tonic-gate 	{xdr_nfslog_READDIRPLUS3args, xdr_nfslog_READDIRPLUS3res, TRUE},
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	/* NFSPROC3_FSSTAT = 18 */
14630Sstevel@tonic-gate 	{xdr_nfslog_FSSTAT3args, xdr_nfslog_FSSTAT3res, FALSE},
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	/* NFSPROC3_FSINFO = 19 */
14660Sstevel@tonic-gate 	{xdr_nfslog_FSINFO3args, xdr_nfslog_FSINFO3res, FALSE},
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	/* NFSPROC3_PATHCONF = 20 */
14690Sstevel@tonic-gate 	{xdr_nfslog_PATHCONF3args, xdr_nfslog_PATHCONF3res, FALSE},
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate 	/* NFSPROC3_COMMIT = 21 */
14720Sstevel@tonic-gate 	{xdr_nfslog_COMMIT3args, xdr_nfslog_COMMIT3res, FALSE},
14730Sstevel@tonic-gate };
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate static struct nfslog_proc_disp nfslog_proc_v1[] = {
14760Sstevel@tonic-gate 	/*
14770Sstevel@tonic-gate 	 * NFSLOG VERSION 1
14780Sstevel@tonic-gate 	 */
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	/* NFSLOG_NULL = 0 */
14810Sstevel@tonic-gate 	{xdr_void, xdr_void, TRUE},
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	/* NFSLOG_SHARE = 1 */
14840Sstevel@tonic-gate 	{xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE},
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	/* NFSLOG_UNSHARE = 2 */
14870Sstevel@tonic-gate 	{xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE},
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	/* NFSLOG_LOOKUP = 3 */
14900Sstevel@tonic-gate 	{xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE},
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	/* NFSLOG_GETFH = 4 */
14930Sstevel@tonic-gate 	{xdr_nfslog_getfhargs, xdr_nfsstat, TRUE},
14940Sstevel@tonic-gate };
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate static struct nfslog_vers_disp nfslog_vers_disptable[] = {
14970Sstevel@tonic-gate 	{sizeof (nfslog_proc_v2) / sizeof (nfslog_proc_v2[0]),
14980Sstevel@tonic-gate 	    nfslog_proc_v2},
14990Sstevel@tonic-gate 	{sizeof (nfslog_proc_v3) / sizeof (nfslog_proc_v3[0]),
15000Sstevel@tonic-gate 	    nfslog_proc_v3},
15010Sstevel@tonic-gate };
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate static struct nfslog_vers_disp nfslog_nfslog_vers_disptable[] = {
15040Sstevel@tonic-gate 	{sizeof (nfslog_proc_v1) / sizeof (nfslog_proc_v1[0]),
15050Sstevel@tonic-gate 	    nfslog_proc_v1},
15060Sstevel@tonic-gate };
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate static struct nfslog_prog_disp nfslog_dispatch_table[] = {
15090Sstevel@tonic-gate 	{NFS_PROGRAM, NFS_VERSMIN,
15100Sstevel@tonic-gate 		(sizeof (nfslog_vers_disptable) /
15110Sstevel@tonic-gate 		sizeof (nfslog_vers_disptable[0])),
15120Sstevel@tonic-gate 		nfslog_vers_disptable},
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	{NFSLOG_PROGRAM, NFSLOG_VERSMIN,
15150Sstevel@tonic-gate 		(sizeof (nfslog_nfslog_vers_disptable) /
15160Sstevel@tonic-gate 		sizeof (nfslog_nfslog_vers_disptable[0])),
15170Sstevel@tonic-gate 		nfslog_nfslog_vers_disptable},
15180Sstevel@tonic-gate };
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate static int	nfslog_dispatch_table_arglen = sizeof (nfslog_dispatch_table) /
15210Sstevel@tonic-gate 					sizeof (nfslog_dispatch_table[0]);
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate /*
15240Sstevel@tonic-gate  * This function will determine the appropriate export info struct to use
15250Sstevel@tonic-gate  * and allocate a record id to be used in the written log buffer.
15260Sstevel@tonic-gate  * Usually this is a straightforward operation but the existence of the
15270Sstevel@tonic-gate  * multicomponent lookup and its semantics of crossing file system
15280Sstevel@tonic-gate  * boundaries add to the complexity.  See the comments below...
15290Sstevel@tonic-gate  */
15300Sstevel@tonic-gate struct exportinfo *
nfslog_get_exi(struct exportinfo * exi,struct svc_req * req,caddr_t res,unsigned int * nfslog_rec_id)15310Sstevel@tonic-gate nfslog_get_exi(
15320Sstevel@tonic-gate 	struct exportinfo *exi,
15330Sstevel@tonic-gate 	struct svc_req *req,
15340Sstevel@tonic-gate 	caddr_t res,
15350Sstevel@tonic-gate 	unsigned int *nfslog_rec_id)
15360Sstevel@tonic-gate {
15370Sstevel@tonic-gate 	struct log_buffer *lb;
15380Sstevel@tonic-gate 	struct exportinfo *exi_ret = NULL;
15391610Sthurlow 	fhandle_t		*fh;
15400Sstevel@tonic-gate 	nfs_fh3			*fh3;
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	if (exi == NULL)
15430Sstevel@tonic-gate 		return (NULL);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	/*
15460Sstevel@tonic-gate 	 * If the exi is marked for logging, allocate a record id and return
15470Sstevel@tonic-gate 	 */
15480Sstevel@tonic-gate 	if (exi->exi_export.ex_flags & EX_LOG) {
15490Sstevel@tonic-gate 		lb = exi->exi_logbuffer;
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 		/* obtain the unique record id for the caller */
15520Sstevel@tonic-gate 		*nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1);
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 		/*
15550Sstevel@tonic-gate 		 * The caller will expect to be able to exi_rele() it,
15560Sstevel@tonic-gate 		 * so exi->exi_count must be incremented before it can
15570Sstevel@tonic-gate 		 * be returned, to make it uniform with exi_ret->exi_count
15580Sstevel@tonic-gate 		 */
1559*12081SThomas.Haynes@Sun.COM 		exi_hold(exi);
15600Sstevel@tonic-gate 		return (exi);
15610Sstevel@tonic-gate 	}
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	if (exi != exi_public)
15640Sstevel@tonic-gate 		return (NULL);
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	/*
15670Sstevel@tonic-gate 	 * Here we have an exi that is not marked for logging.
15680Sstevel@tonic-gate 	 * It is possible that this request is a multicomponent lookup
15690Sstevel@tonic-gate 	 * that was done from the public file handle (not logged) and
15700Sstevel@tonic-gate 	 * the resulting file handle being returned to the client exists
15710Sstevel@tonic-gate 	 * in a file system that is being logged.  If this is the case
15720Sstevel@tonic-gate 	 * we need to log this multicomponent lookup to the appropriate
15730Sstevel@tonic-gate 	 * log buffer.  This will allow for the appropriate path name
15740Sstevel@tonic-gate 	 * mapping to occur at user level.
15750Sstevel@tonic-gate 	 */
15760Sstevel@tonic-gate 	if (req->rq_prog == NFS_PROGRAM) {
15770Sstevel@tonic-gate 		switch (req->rq_vers) {
15780Sstevel@tonic-gate 		case NFS_V3:
15790Sstevel@tonic-gate 			if ((req->rq_proc == NFSPROC3_LOOKUP) &&
15805112Sbatschul 			    (((LOOKUP3res *)res)->status == NFS3_OK)) {
15810Sstevel@tonic-gate 				fh3 = &((LOOKUP3res *)res)->res_u.ok.object;
15821610Sthurlow 				exi_ret = checkexport(&fh3->fh3_fsid,
15835112Sbatschul 				    FH3TOXFIDP(fh3));
15840Sstevel@tonic-gate 			}
15850Sstevel@tonic-gate 			break;
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 		case NFS_VERSION:
15880Sstevel@tonic-gate 			if ((req->rq_proc == RFS_LOOKUP) &&
15895112Sbatschul 			    (((struct nfsdiropres *)
15905112Sbatschul 			    res)->dr_status == NFS_OK)) {
15915112Sbatschul 				fh =  &((struct nfsdiropres *)res)->
15925112Sbatschul 				    dr_u.dr_drok_u.drok_fhandle;
15931610Sthurlow 				exi_ret = checkexport(&fh->fh_fsid,
15945112Sbatschul 				    (fid_t *)&fh->fh_xlen);
15950Sstevel@tonic-gate 			}
15960Sstevel@tonic-gate 			break;
15970Sstevel@tonic-gate 		default:
15980Sstevel@tonic-gate 			break;
15990Sstevel@tonic-gate 		}
16000Sstevel@tonic-gate 	}
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	if (exi_ret != NULL && exi_ret->exi_export.ex_flags & EX_LOG) {
16030Sstevel@tonic-gate 		lb = exi_ret->exi_logbuffer;
16040Sstevel@tonic-gate 		/* obtain the unique record id for the caller */
16050Sstevel@tonic-gate 		*nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1);
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 		return (exi_ret);
16080Sstevel@tonic-gate 	}
16090Sstevel@tonic-gate 	return (NULL);
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate #ifdef DEBUG
16130Sstevel@tonic-gate static long long rfslog_records_ignored = 0;
16140Sstevel@tonic-gate #endif
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate /*
16170Sstevel@tonic-gate  * nfslog_write_record - Fill in the record buffer for writing out.
16180Sstevel@tonic-gate  * If logrecp is null, log it, otherwise, malloc the record and return it.
16190Sstevel@tonic-gate  *
16200Sstevel@tonic-gate  * It is the responsibility of the caller to check whether this exportinfo
16210Sstevel@tonic-gate  * has logging enabled.
16220Sstevel@tonic-gate  * Note that nfslog_share_public_record() only needs to check for the
16230Sstevel@tonic-gate  * existence of at least one logbuffer to which the public filehandle record
16240Sstevel@tonic-gate  * needs to be logged.
16250Sstevel@tonic-gate  */
16260Sstevel@tonic-gate void
nfslog_write_record(struct exportinfo * exi,struct svc_req * req,caddr_t args,caddr_t res,cred_t * cr,struct netbuf * pnb,unsigned int record_id,unsigned int which_buffers)16270Sstevel@tonic-gate nfslog_write_record(struct exportinfo *exi, struct svc_req *req,
16280Sstevel@tonic-gate 	caddr_t args, caddr_t res, cred_t *cr, struct netbuf *pnb,
16290Sstevel@tonic-gate 	unsigned int record_id, unsigned int which_buffers)
16300Sstevel@tonic-gate {
16310Sstevel@tonic-gate 	struct nfslog_prog_disp	*progtable;	/* prog struct */
16320Sstevel@tonic-gate 	struct nfslog_vers_disp	*verstable;	/* version struct */
16330Sstevel@tonic-gate 	struct nfslog_proc_disp	*disp = NULL;	/* proc struct */
16340Sstevel@tonic-gate 	int			i, vers;
16350Sstevel@tonic-gate 	void			*log_cookie;	/* for logrecord if */
16360Sstevel@tonic-gate 	caddr_t			buffer;
16370Sstevel@tonic-gate 	XDR			xdrs;
16380Sstevel@tonic-gate 	unsigned int		final_size;
16390Sstevel@tonic-gate 	int			encode_ok;
16400Sstevel@tonic-gate 	int			alloc_indx;
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	ASSERT(exi != NULL); ASSERT(req != NULL); ASSERT(args != NULL);
16430Sstevel@tonic-gate 	ASSERT(res != NULL); ASSERT(cr != NULL);
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 	/*
16460Sstevel@tonic-gate 	 * Find program element
16470Sstevel@tonic-gate 	 * Search the list since program can not be used as index
16480Sstevel@tonic-gate 	 */
16490Sstevel@tonic-gate 	for (i = 0; (i < nfslog_dispatch_table_arglen); i++) {
16500Sstevel@tonic-gate 		if (req->rq_prog == nfslog_dispatch_table[i].nfslog_dis_prog)
16510Sstevel@tonic-gate 			break;
16520Sstevel@tonic-gate 	}
16530Sstevel@tonic-gate 	if (i >= nfslog_dispatch_table_arglen) {	/* program not logged */
16540Sstevel@tonic-gate 		/* not an error */
16550Sstevel@tonic-gate 		return;
16560Sstevel@tonic-gate 	}
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	/*
16590Sstevel@tonic-gate 	 * Extract the dispatch functions based on program/version
16600Sstevel@tonic-gate 	 */
16610Sstevel@tonic-gate 	progtable = &nfslog_dispatch_table[i];
16620Sstevel@tonic-gate 	vers = req->rq_vers - progtable->nfslog_dis_versmin;
16630Sstevel@tonic-gate 	verstable = &progtable->nfslog_dis_vers_table[vers];
16640Sstevel@tonic-gate 	disp = &verstable->nfslog_dis_proc_table[req->rq_proc];
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 	if (!(exi->exi_export.ex_flags & EX_LOG_ALLOPS) &&
16670Sstevel@tonic-gate 	    !disp->affects_transactions) {
16680Sstevel@tonic-gate 		/*
16690Sstevel@tonic-gate 		 * Only interested in logging operations affecting
16700Sstevel@tonic-gate 		 * transaction generation. This is not one of them.
16710Sstevel@tonic-gate 		 */
16720Sstevel@tonic-gate #ifdef DEBUG
16730Sstevel@tonic-gate 		rfslog_records_ignored++;
16740Sstevel@tonic-gate #endif
16750Sstevel@tonic-gate 		return;
16760Sstevel@tonic-gate 	}
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 	switch (req->rq_prog) {
16790Sstevel@tonic-gate 	case NFS_PROGRAM:
16800Sstevel@tonic-gate 		switch (req->rq_vers) {
16810Sstevel@tonic-gate 		case NFS_V3:
16820Sstevel@tonic-gate 			switch (req->rq_proc) {
16830Sstevel@tonic-gate 			case NFSPROC3_READDIRPLUS:
16840Sstevel@tonic-gate 				alloc_indx = MEDIUM_INDX;
16850Sstevel@tonic-gate 				break;
16860Sstevel@tonic-gate 			default:
16870Sstevel@tonic-gate 				alloc_indx = SMALL_INDX;
16880Sstevel@tonic-gate 				break;
16890Sstevel@tonic-gate 			}
16900Sstevel@tonic-gate 			break;
16910Sstevel@tonic-gate 		default:
16920Sstevel@tonic-gate 			alloc_indx = SMALL_INDX;
16930Sstevel@tonic-gate 			break;
16940Sstevel@tonic-gate 		}
16950Sstevel@tonic-gate 		break;
16960Sstevel@tonic-gate 	case NFSLOG_PROGRAM:
16970Sstevel@tonic-gate 		alloc_indx = MEDIUM_INDX;
16980Sstevel@tonic-gate 		break;
16990Sstevel@tonic-gate 	default:
17000Sstevel@tonic-gate 		alloc_indx = SMALL_INDX;
17010Sstevel@tonic-gate 		break;
17020Sstevel@tonic-gate 	}
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	do {
17050Sstevel@tonic-gate 		encode_ok = FALSE;
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 		/* Pick the size to alloc; end of the road - return */
17080Sstevel@tonic-gate 		if (nfslog_mem_alloc[alloc_indx].size == (-1)) {
17090Sstevel@tonic-gate 			cmn_err(CE_WARN,
17105112Sbatschul 			    "NFSLOG: unable to encode record - prog=%d "
17115112Sbatschul 			    "proc = %d", req->rq_prog, req->rq_proc);
17120Sstevel@tonic-gate 			return;
17130Sstevel@tonic-gate 		}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 		buffer = nfslog_record_alloc(exi, alloc_indx, &log_cookie, 0);
17160Sstevel@tonic-gate 		if (buffer == NULL) {
17170Sstevel@tonic-gate 			/* Error processing - no space alloced */
17180Sstevel@tonic-gate 			rfs_log_bad++;
17190Sstevel@tonic-gate 			cmn_err(CE_WARN, "NFSLOG: can't get record");
17200Sstevel@tonic-gate 			return;
17210Sstevel@tonic-gate 		}
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 		xdrmem_create(&xdrs, buffer,
17245112Sbatschul 		    nfslog_mem_alloc[alloc_indx].size, XDR_ENCODE);
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 		/*
17270Sstevel@tonic-gate 		 * Encode the header, args and results of the record
17280Sstevel@tonic-gate 		 */
17290Sstevel@tonic-gate 		if (xdr_nfslog_request_record(&xdrs, exi, req, cr, pnb,
17305112Sbatschul 		    nfslog_mem_alloc[alloc_indx].size, record_id) &&
17315112Sbatschul 		    (*disp->xdrargs)(&xdrs, args) &&
17325112Sbatschul 		    (*disp->xdrres)(&xdrs, res)) {
17330Sstevel@tonic-gate 				encode_ok = TRUE;
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 				rfs_log_good++;
17360Sstevel@tonic-gate 				/*
17370Sstevel@tonic-gate 				 * Get the final size of the encoded
17380Sstevel@tonic-gate 				 * data and insert that length at the
17390Sstevel@tonic-gate 				 * beginning.
17400Sstevel@tonic-gate 				 */
17410Sstevel@tonic-gate 				final_size = xdr_getpos(&xdrs);
17420Sstevel@tonic-gate 				xdr_setpos(&xdrs, 0);
17430Sstevel@tonic-gate 				(void) xdr_u_int(&xdrs, &final_size);
17440Sstevel@tonic-gate 		} else {
17450Sstevel@tonic-gate 			/* Oops, the encode failed so we need to free memory */
17460Sstevel@tonic-gate 			nfslog_record_put(log_cookie, 0, FALSE, which_buffers);
17470Sstevel@tonic-gate 			alloc_indx++;
17480Sstevel@tonic-gate 		}
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	} while (encode_ok == FALSE);
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	/*
17540Sstevel@tonic-gate 	 * Take the final log record and put it in the log file.
17550Sstevel@tonic-gate 	 * This may be queued to the file internally and written
17560Sstevel@tonic-gate 	 * later unless the last parameter is TRUE.
17570Sstevel@tonic-gate 	 * If the record_id is 0 then this is most likely a share/unshare
17580Sstevel@tonic-gate 	 * request and it should be written synchronously to the log file.
17590Sstevel@tonic-gate 	 */
17605112Sbatschul 	nfslog_record_put(log_cookie,
17615112Sbatschul 	    final_size, (record_id == 0), which_buffers);
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate static char *
get_publicfh_path(int * alloc_length)17650Sstevel@tonic-gate get_publicfh_path(int *alloc_length)
17660Sstevel@tonic-gate {
17670Sstevel@tonic-gate 	extern struct exportinfo *exi_public;
17680Sstevel@tonic-gate 	char *pubpath;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	rw_enter(&exported_lock, RW_READER);
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	*alloc_length = exi_public->exi_export.ex_pathlen + 1;
17730Sstevel@tonic-gate 	pubpath = kmem_alloc(*alloc_length, KM_SLEEP);
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	(void) strcpy(pubpath, exi_public->exi_export.ex_path);
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	rw_exit(&exported_lock);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	return (pubpath);
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate static void
log_public_record(struct exportinfo * exi,cred_t * cr)17830Sstevel@tonic-gate log_public_record(struct exportinfo *exi, cred_t *cr)
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate 	struct svc_req	req;
17860Sstevel@tonic-gate 	struct netbuf	nb = {0, 0, NULL};
17870Sstevel@tonic-gate 	int free_length = 0;
17880Sstevel@tonic-gate 	diropargs3 args;
17890Sstevel@tonic-gate 	LOOKUP3res res;
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	bzero(&req, sizeof (req));
17920Sstevel@tonic-gate 	req.rq_prog = NFSLOG_PROGRAM;
17930Sstevel@tonic-gate 	req.rq_vers = NFSLOG_VERSION;
17940Sstevel@tonic-gate 	req.rq_proc = NFSLOG_LOOKUP;
17950Sstevel@tonic-gate 	req.rq_cred.oa_flavor = AUTH_NONE;
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	bzero(&args, sizeof (diropargs3));
17980Sstevel@tonic-gate 	bzero(&res, sizeof (LOOKUP3res));
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	args.dir.fh3_length = 0;
18010Sstevel@tonic-gate 	if ((args.name = get_publicfh_path(&free_length)) == NULL)
18020Sstevel@tonic-gate 		return;
18030Sstevel@tonic-gate 	args.dirp = &args.dir;
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 	res.status = NFS3_OK;
18060Sstevel@tonic-gate 	res.res_u.ok.object.fh3_length = 0;
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	/*
18090Sstevel@tonic-gate 	 * Calling this function with the exi_public
18100Sstevel@tonic-gate 	 * will have the effect of appending the record
18110Sstevel@tonic-gate 	 * to each of the open log buffers
18120Sstevel@tonic-gate 	 */
18130Sstevel@tonic-gate 	nfslog_write_record(exi, &req,
18145112Sbatschul 	    (caddr_t)&args, (caddr_t)&res, cr, &nb, 0, NFSLOG_ALL_BUFFERS);
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	kmem_free(args.name, free_length);
18170Sstevel@tonic-gate }
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate /*
18200Sstevel@tonic-gate  * nfslog_share_record - logs a share request.
18210Sstevel@tonic-gate  * This is not an NFS request, but we pretend here...
18220Sstevel@tonic-gate  */
18230Sstevel@tonic-gate void
nfslog_share_record(struct exportinfo * exi,cred_t * cr)18240Sstevel@tonic-gate nfslog_share_record(struct exportinfo *exi, cred_t *cr)
18250Sstevel@tonic-gate {
18260Sstevel@tonic-gate 	struct svc_req	req;
18270Sstevel@tonic-gate 	int		res = 0;
18280Sstevel@tonic-gate 	struct netbuf	nb = {0, 0, NULL};
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate 	ASSERT(exi != NULL);
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	if (nfslog_buffer_list == NULL)
18330Sstevel@tonic-gate 		return;
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	if (exi->exi_export.ex_flags & EX_LOG) {
18360Sstevel@tonic-gate 		bzero(&req, sizeof (req));
18370Sstevel@tonic-gate 		req.rq_prog = NFSLOG_PROGRAM;
18380Sstevel@tonic-gate 		req.rq_vers = NFSLOG_VERSION;
18390Sstevel@tonic-gate 		req.rq_proc = NFSLOG_SHARE;
18400Sstevel@tonic-gate 		req.rq_cred.oa_flavor = AUTH_NONE;
18415112Sbatschul 		nfslog_write_record(exi, &req, (caddr_t)exi, (caddr_t)&res, cr,
18425112Sbatschul 		    &nb, 0, NFSLOG_ONE_BUFFER);
18430Sstevel@tonic-gate 	}
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 	log_public_record(exi, cr);
18460Sstevel@tonic-gate }
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate /*
18490Sstevel@tonic-gate  * nfslog_unshare_record - logs an unshare request.
18500Sstevel@tonic-gate  * This is not an NFS request, but we pretend here...
18510Sstevel@tonic-gate  */
18520Sstevel@tonic-gate void
nfslog_unshare_record(struct exportinfo * exi,cred_t * cr)18530Sstevel@tonic-gate nfslog_unshare_record(struct exportinfo *exi, cred_t *cr)
18540Sstevel@tonic-gate {
18550Sstevel@tonic-gate 	struct svc_req	req;
18560Sstevel@tonic-gate 	int		res = 0;
18570Sstevel@tonic-gate 	struct netbuf	nb = {0, 0, NULL};
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	ASSERT(exi != NULL);
18600Sstevel@tonic-gate 	ASSERT(exi->exi_export.ex_flags & EX_LOG);
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	bzero(&req, sizeof (req));
18630Sstevel@tonic-gate 	req.rq_prog = NFSLOG_PROGRAM;
18640Sstevel@tonic-gate 	req.rq_vers = NFSLOG_VERSION;
18650Sstevel@tonic-gate 	req.rq_proc = NFSLOG_UNSHARE;
18660Sstevel@tonic-gate 	req.rq_cred.oa_flavor = AUTH_NONE;
18670Sstevel@tonic-gate 	nfslog_write_record(exi, &req,
18685112Sbatschul 	    (caddr_t)exi, (caddr_t)&res, cr, &nb, 0, NFSLOG_ONE_BUFFER);
18690Sstevel@tonic-gate }
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate void
nfslog_getfh(struct exportinfo * exi,fhandle * fh,char * fname,enum uio_seg seg,cred_t * cr)18730Sstevel@tonic-gate nfslog_getfh(struct exportinfo *exi,
18740Sstevel@tonic-gate 	fhandle *fh,
18750Sstevel@tonic-gate 	char *fname,
18760Sstevel@tonic-gate 	enum uio_seg seg,
18770Sstevel@tonic-gate 	cred_t *cr)
18780Sstevel@tonic-gate {
18790Sstevel@tonic-gate 	struct svc_req	req;
18800Sstevel@tonic-gate 	int		res = 0;
18810Sstevel@tonic-gate 	struct netbuf	nb = {0, 0, NULL};
18820Sstevel@tonic-gate 	int		error = 0;
18830Sstevel@tonic-gate 	char		*namebuf;
18840Sstevel@tonic-gate 	size_t		len;
18850Sstevel@tonic-gate 	nfslog_getfhargs gfh;
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	ASSERT(exi != NULL);
18880Sstevel@tonic-gate 	ASSERT(exi->exi_export.ex_flags & EX_LOG);
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	bzero(&req, sizeof (req));
18910Sstevel@tonic-gate 	req.rq_prog = NFSLOG_PROGRAM;
18920Sstevel@tonic-gate 	req.rq_vers = NFSLOG_VERSION;
18930Sstevel@tonic-gate 	req.rq_proc = NFSLOG_GETFH;
18940Sstevel@tonic-gate 	req.rq_cred.oa_flavor = AUTH_NONE;
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	namebuf = kmem_alloc(MAXPATHLEN + 4, KM_SLEEP);
18970Sstevel@tonic-gate 	if (seg == UIO_USERSPACE) {
18980Sstevel@tonic-gate 		error = copyinstr(fname, namebuf, MAXPATHLEN, &len);
18990Sstevel@tonic-gate 	} else {
19000Sstevel@tonic-gate 		error = copystr(fname, namebuf, MAXPATHLEN, &len);
19010Sstevel@tonic-gate 	}
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 	if (!error) {
19040Sstevel@tonic-gate 		gfh.gfh_fh_buf = *fh;
19050Sstevel@tonic-gate 		gfh.gfh_path = namebuf;
19060Sstevel@tonic-gate 
19075112Sbatschul 		nfslog_write_record(exi, &req, (caddr_t)&gfh, (caddr_t)&res,
19085112Sbatschul 		    cr, &nb, 0, NFSLOG_ONE_BUFFER);
19090Sstevel@tonic-gate 	}
19100Sstevel@tonic-gate 	kmem_free(namebuf, MAXPATHLEN + 4);
19110Sstevel@tonic-gate }
1912