Home | History | Annotate | Download | only in nfs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/cred.h>
     29 #include <sys/cmn_err.h>
     30 #include <sys/debug.h>
     31 #include <sys/systm.h>
     32 #include <sys/kmem.h>
     33 #include <sys/disp.h>
     34 #include <sys/atomic.h>
     35 #include <rpc/types.h>
     36 #include <nfs/nfs.h>
     37 #include <nfs/nfssys.h>
     38 #include <nfs/export.h>
     39 #include <nfs/rnode.h>
     40 #include <rpc/auth.h>
     41 #include <rpc/svc.h>
     42 #include <rpc/xdr.h>
     43 #include <rpc/clnt.h>
     44 #include <nfs/nfs_log.h>
     45 
     46 #define	NUM_RECORDS_TO_WRITE 256
     47 #define	NUM_BYTES_TO_WRITE 65536
     48 
     49 extern krwlock_t exported_lock;
     50 
     51 static int nfslog_num_records_to_write = NUM_RECORDS_TO_WRITE;
     52 static int nfslog_num_bytes_to_write = NUM_BYTES_TO_WRITE;
     53 
     54 /*
     55  * This struct is used to 'hide' the details of managing the log
     56  * records internally to the logging code.  Allocation routines
     57  * are used to obtain pieces of memory for XDR encoding.  This struct
     58  * is a 'header' to those areas and a opaque cookie is used to pass
     59  * this data structure between the allocating function and the put
     60  * function.
     61  */
     62 struct lr_alloc {
     63 	struct lr_alloc		*next;		/* links for write queuing */
     64 	struct lr_alloc		*prev;
     65 #define	LR_ALLOC_NOFREE	0x1			/* not present, call free */
     66 	int			lr_flags;
     67 	caddr_t			log_record;	/* address to XDR encoding */
     68 	size_t			size;		/* final size of encoding */
     69 	struct kmem_cache	*alloc_cache;	/* keep track of cache ptr */
     70 	struct exportinfo	*exi;		/* who are we related to? */
     71 	struct log_buffer	*lb;
     72 };
     73 
     74 struct flush_thread_params {
     75 	struct nfsl_flush_args tp_args;
     76 	int tp_error;
     77 };
     78 
     79 static int log_file_create(caddr_t, struct log_file **);
     80 static void log_file_rele(struct log_file *);
     81 static struct log_buffer *log_buffer_create(caddr_t);
     82 static void log_buffer_rele(struct log_buffer *);
     83 static int nfslog_record_append2all(struct lr_alloc *);
     84 static int nfslog_logbuffer_rename(struct log_buffer *);
     85 static void nfslog_logfile_wait(struct log_file *);
     86 static int nfslog_logfile_rename(char *, char *);
     87 static void nfslog_do_flush(struct flush_thread_params *);
     88 static void create_buffer_header(caddr_t *, size_t *, size_t *);
     89 
     90 static int nfslog_write_logrecords(struct log_file *, struct lr_alloc *, int);
     91 static void nfslog_free_logrecords(struct lr_alloc *);
     92 static int nfslog_records_flush_to_disk(struct log_buffer *);
     93 static int nfslog_records_flush_to_disk_nolock(struct log_buffer *);
     94 
     95 /*
     96  * Read/Write lock that protects 'nfslog_buffer_list'.
     97  * This lock must be held when searching or modifying 'nfslog_buffer_list'.
     98  */
     99 static krwlock_t nfslog_buffer_list_lock;
    100 
    101 /*
    102  * The list of "log_buffer" structures.
    103  */
    104 struct log_buffer *nfslog_buffer_list = NULL;
    105 
    106 
    107 #define	LOG_BUFFER_HOLD(lbp)	{ \
    108 	mutex_enter(&(lbp)->lb_lock); \
    109 	(lbp)->lb_refcnt++; \
    110 	mutex_exit(&(lbp)->lb_lock); \
    111 }
    112 
    113 #define	LOG_FILE_HOLD(lfp)	{ \
    114 	mutex_enter(&(lfp)->lf_lock); \
    115 	(lfp)->lf_refcnt++; \
    116 	mutex_exit(&(lfp)->lf_lock); \
    117 }
    118 
    119 #define	LOG_FILE_RELE(lfp)	{ \
    120 	log_file_rele(lfp); \
    121 }
    122 
    123 /*
    124  * These two macros are used to prep a logfile data structure and
    125  * associated file for writing data.  Note that the lf_lock is
    126  * held as a result of the call to the first macro.  This is used
    127  * for serialization correctness between the logbuffer struct and
    128  * the logfile struct.
    129  */
    130 #define	LOG_FILE_LOCK_TO_WRITE(lfp)	{ \
    131 	mutex_enter(&(lfp)->lf_lock); \
    132 	(lfp)->lf_refcnt++; \
    133 	(lfp)->lf_writers++; \
    134 }
    135 
    136 #define	LOG_FILE_UNLOCK_FROM_WRITE(lfp)	{ \
    137 	(lfp)->lf_writers--; \
    138 	if ((lfp)->lf_writers == 0 && ((lfp)->lf_flags & L_WAITING)) { \
    139 		(lfp)->lf_flags &= ~L_WAITING; \
    140 		cv_broadcast(&(lfp)->lf_cv_waiters); \
    141 	} \
    142 	mutex_exit(&(lfp)->lf_lock); \
    143 	log_file_rele(lfp); \
    144 }
    145 
    146 int rfsl_log_buffer = 0;
    147 static int rfsl_log_file = 0;
    148 
    149 /* This array is used for memory allocation of record encoding spaces */
    150 static struct {
    151 	int	size;
    152 	struct kmem_cache *mem_cache;
    153 	char	*cache_name;
    154 } nfslog_mem_alloc[] = {
    155 #define	SMALL_INDX 0
    156 	{ NFSLOG_SMALL_RECORD_SIZE - sizeof (struct lr_alloc),
    157 	NULL, NFSLOG_SMALL_REC_NAME },
    158 #define	MEDIUM_INDX 1
    159 	{ NFSLOG_MEDIUM_RECORD_SIZE - sizeof (struct lr_alloc),
    160 	NULL, NFSLOG_MEDIUM_REC_NAME },
    161 #define	LARGE_INDX 2
    162 	{ NFSLOG_LARGE_RECORD_SIZE - sizeof (struct lr_alloc),
    163 	NULL, NFSLOG_LARGE_REC_NAME },
    164 	{ (-1), NULL }
    165 };
    166 
    167 /* Used to calculate the 'real' allocation size */
    168 #define	ALLOC_SIZE(index) \
    169 	(nfslog_mem_alloc[index].size + sizeof (struct lr_alloc))
    170 
    171 /*
    172  * Initialize logging data buffer cache
    173  */
    174 void
    175 nfslog_init()
    176 {
    177 	int indx;
    178 
    179 	rw_init(&nfslog_buffer_list_lock, NULL, RW_DEFAULT, NULL);
    180 
    181 	/*
    182 	 * Initialize the kmem caches for encoding
    183 	 */
    184 	for (indx = 0; nfslog_mem_alloc[indx].size != (-1); indx++) {
    185 		nfslog_mem_alloc[indx].mem_cache =
    186 		    kmem_cache_create(nfslog_mem_alloc[indx].cache_name,
    187 		    ALLOC_SIZE(indx), 0, NULL, NULL, NULL, NULL, NULL, 0);
    188 	}
    189 }
    190 
    191 /*
    192  * Sets up the necessary log file and related buffers to enable logging
    193  * on the given export point.
    194  * Returns 0 on success, non-zero on failure.
    195  */
    196 int
    197 nfslog_setup(struct exportinfo *exi)
    198 {
    199 	struct exportdata *kex;
    200 	struct log_buffer *lbp;
    201 	struct log_buffer *nlbp;
    202 
    203 	kex = &exi->exi_export;
    204 	ASSERT(kex->ex_flags & EX_LOG);
    205 
    206 	/*
    207 	 * Logging is enabled for the new export point, check
    208 	 * the existing log_buffer structures to see if the
    209 	 * desired buffer has already been opened. If so, point
    210 	 * the new exportinfo's exi_logbuffer to the existing
    211 	 * one.
    212 	 */
    213 	rw_enter(&nfslog_buffer_list_lock, RW_READER);
    214 	for (lbp = nfslog_buffer_list; lbp != NULL; lbp = lbp->lb_next) {
    215 		LOGGING_DPRINT((10,
    216 		    "searching for buffer... found log_buffer '%s'\n",
    217 		    lbp->lb_path));
    218 		if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) {
    219 			/* Found our match. Ref it and return */
    220 			LOG_BUFFER_HOLD(lbp);
    221 			exi->exi_logbuffer = lbp;
    222 			LOGGING_DPRINT((10,  "\tfound log_buffer for '%s'\n",
    223 			    kex->ex_log_buffer));
    224 			rw_exit(&nfslog_buffer_list_lock);
    225 			return (0);
    226 		}
    227 	}
    228 	rw_exit(&nfslog_buffer_list_lock);
    229 
    230 	/*
    231 	 * New buffer needed, allocate it.
    232 	 * The buffer list lock has been dropped so we will need to search
    233 	 * the list again to ensure that another thread has not added
    234 	 * a matching buffer.
    235 	 */
    236 	if ((nlbp = log_buffer_create(kex->ex_log_buffer)) == NULL) {
    237 		/*
    238 		 * Failed the buffer creation for some reason so we
    239 		 * will need to return.
    240 		 */
    241 		return (EIO);
    242 	}
    243 
    244 	rw_enter(&nfslog_buffer_list_lock, RW_WRITER);
    245 	for (lbp = nfslog_buffer_list; lbp != NULL;
    246 	    lbp = lbp->lb_next) {
    247 		if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) {
    248 				/*
    249 				 * A log_buffer already exists for the
    250 				 * indicated buffer, use it instead.
    251 				 */
    252 			LOG_BUFFER_HOLD(lbp);
    253 
    254 			exi->exi_logbuffer = lbp;
    255 
    256 			LOGGING_DPRINT((10, "found log_buffer for '%s' "
    257 			    "after allocation\n", kex->ex_log_buffer));
    258 
    259 			rw_exit(&nfslog_buffer_list_lock);
    260 
    261 			log_buffer_rele(nlbp);
    262 
    263 			return (0);
    264 		}
    265 	}
    266 	/*
    267 	 * Didn't find an existing log_buffer for this buffer,
    268 	 * use the the newly created one, and add to list.  We
    269 	 * increment the reference count because the node is
    270 	 * entered into the global list.
    271 	 */
    272 	LOGGING_DPRINT((10, "exportfs: adding nlbp=%p to list\n",
    273 	    (void *)nlbp));
    274 
    275 	nlbp->lb_next = nfslog_buffer_list;
    276 	nfslog_buffer_list = nlbp;
    277 
    278 	LOG_BUFFER_HOLD(nlbp);	/* hold is for export entry */
    279 	exi->exi_logbuffer = nlbp;
    280 
    281 	rw_exit(&nfslog_buffer_list_lock);
    282 
    283 	return (0);
    284 }
    285 
    286 /*
    287  * Disables logging for the given export point.
    288  */
    289 void
    290 nfslog_disable(struct exportinfo *exi)
    291 {
    292 	log_buffer_rele(exi->exi_logbuffer);
    293 }
    294 
    295 /*
    296  * Creates the corresponding log_buffer and log_file structures
    297  * for the the buffer named 'name'.
    298  * Returns a pointer to the log_buffer structure with reference one.
    299  */
    300 static struct log_buffer *
    301 log_buffer_create(caddr_t name)
    302 {
    303 	struct log_buffer *buffer;
    304 	struct log_file *logfile;
    305 	int namelen = strlen(name);
    306 
    307 	LOGGING_DPRINT((10,  "log_buffer_create: %s\n", name));
    308 	if (log_file_create(name, &logfile))
    309 		return (NULL);
    310 
    311 	buffer = (struct log_buffer *)kmem_alloc(sizeof (*buffer), KM_SLEEP);
    312 	buffer->lb_refcnt = 1;
    313 	buffer->lb_rec_id = 0;
    314 	buffer->lb_path = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP);
    315 	bcopy(name, buffer->lb_path, namelen + 1);
    316 	buffer->lb_logfile = logfile;
    317 	buffer->lb_records = NULL;
    318 	buffer->lb_num_recs = 0;
    319 	buffer->lb_size_queued = 0;
    320 	mutex_init(&buffer->lb_lock, NULL, MUTEX_DEFAULT, NULL);
    321 	rfsl_log_buffer++;
    322 
    323 	return (buffer);
    324 }
    325 
    326 /*
    327  * Release a log_buffer structure
    328  */
    329 static void
    330 log_buffer_rele(struct log_buffer *lbp)
    331 {
    332 	int len;
    333 
    334 	mutex_enter(&lbp->lb_lock);
    335 	if (--lbp->lb_refcnt > 1) {
    336 		mutex_exit(&lbp->lb_lock);
    337 		return;
    338 	}
    339 
    340 	if (lbp->lb_refcnt < 0) {
    341 		panic("log_rele: log_buffer refcnt < 0");
    342 		/*NOTREACHED*/
    343 	}
    344 
    345 	/*
    346 	 * Need to drop the lb_lock before acquiring the
    347 	 * nfslog_buffer_list_lock. To avoid double free we need
    348 	 * to hold an additional reference to the log buffer.
    349 	 * This will ensure that no two threads will simultaneously
    350 	 * be trying to free the same log buffer.
    351 	 */
    352 
    353 	if (lbp->lb_refcnt == 1) {
    354 
    355 		/*
    356 		 * If the ref count is 1, then the last
    357 		 * unshare/reference has been given up and we need to
    358 		 * clean up the buffer and remove it from the buffer
    359 		 * list.
    360 		 */
    361 		LOGGING_DPRINT((10,
    362 		    "log_buffer_rele lbp=%p disconnecting\n", (void *)lbp));
    363 		/*
    364 		 * Hold additional reference before dropping the lb_lock
    365 		 */
    366 
    367 		lbp->lb_refcnt++;
    368 		mutex_exit(&lbp->lb_lock);
    369 
    370 		/*
    371 		 * Make sure that all of the buffered records are written.
    372 		 * Don't bother checking the write return value since there
    373 		 * isn't much we can do at this point.
    374 		 */
    375 		(void) nfslog_records_flush_to_disk(lbp);
    376 
    377 		rw_enter(&nfslog_buffer_list_lock, RW_WRITER);
    378 		mutex_enter(&lbp->lb_lock);
    379 		/*
    380 		 * Drop the reference count held above.
    381 		 * If the ref count is still > 1 then someone has
    382 		 * stepped in to use this log buffer.  unlock and return.
    383 		 */
    384 		if (--lbp->lb_refcnt > 1) {
    385 			mutex_exit(&lbp->lb_lock);
    386 			rw_exit(&nfslog_buffer_list_lock);
    387 			return;
    388 		}
    389 
    390 		if (lbp == nfslog_buffer_list) {
    391 			nfslog_buffer_list = lbp->lb_next;
    392 		} else {
    393 			struct log_buffer *tlbp;
    394 
    395 			/* Drop the log_buffer from the master list */
    396 			for (tlbp = nfslog_buffer_list; tlbp->lb_next != NULL;
    397 			    tlbp = tlbp->lb_next) {
    398 				if (tlbp->lb_next == lbp) {
    399 					tlbp->lb_next = lbp->lb_next;
    400 					break;
    401 				}
    402 			}
    403 		}
    404 
    405 		mutex_exit(&lbp->lb_lock);
    406 		rw_exit(&nfslog_buffer_list_lock);
    407 	}
    408 	/*
    409 	 * ref count zero; finish clean up.
    410 	 */
    411 	LOGGING_DPRINT((10, "log_buffer_rele lbp=%p freeing\n", (void *)lbp));
    412 
    413 	log_file_rele(lbp->lb_logfile);
    414 	len = strlen(lbp->lb_path) + 1;
    415 	kmem_free(lbp->lb_path, len);
    416 	kmem_free(lbp, sizeof (*lbp));
    417 	rfsl_log_buffer--;
    418 }
    419 
    420 /*
    421  * Creates the corresponding log_file structure for the buffer
    422  * named 'log_file_name'.
    423  * 'log_file_name' is created by concatenating 'origname' and LOG_INPROG_STRING.
    424  * 'logfile' is set to be the log_file structure with reference one.
    425  */
    426 static int
    427 log_file_create(caddr_t origname, struct log_file **lfpp)
    428 {
    429 	vnode_t *vp = NULL;
    430 	char *name;
    431 	int namelen;
    432 	int error;
    433 	struct log_file *logfile = NULL;
    434 	vattr_t va;
    435 	caddr_t loghdr = NULL;
    436 	size_t loghdr_len = 0;
    437 	size_t loghdr_free = 0;
    438 
    439 	namelen = strlen(origname) + strlen(LOG_INPROG_STRING);
    440 	name = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP);
    441 	(void) sprintf(name, "%s%s", origname, LOG_INPROG_STRING);
    442 
    443 	LOGGING_DPRINT((3, "log_file_create: %s\n", name));
    444 	if (error = vn_open(name, UIO_SYSSPACE, FCREAT|FWRITE|FOFFMAX,
    445 	    LOG_MODE, &vp, CRCREAT, 0)) {
    446 		nfs_cmn_err(error, CE_WARN,
    447 		    "log_file_create: Can not open %s - error %m", name);
    448 		goto out;
    449 	}
    450 	LOGGING_DPRINT((3, "log_file_create: %s vp=%p v_count=%d\n",
    451 	    name, (void *)vp, vp->v_count));
    452 
    453 	logfile = (struct log_file *)kmem_zalloc(sizeof (*logfile), KM_SLEEP);
    454 	logfile->lf_path = name;
    455 	/*
    456 	 * No need to bump the vnode reference count since it is set
    457 	 * to one by vn_open().
    458 	 */
    459 	logfile->lf_vp = vp;
    460 	logfile->lf_refcnt = 1;
    461 	mutex_init(&logfile->lf_lock, NULL, MUTEX_DEFAULT, NULL);
    462 	rfsl_log_file++;
    463 
    464 	va.va_mask = AT_SIZE;
    465 	error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
    466 	if (error) {
    467 		nfs_cmn_err(error, CE_WARN,
    468 		    "log_file_create: Can not stat %s - error = %m",  name);
    469 		goto out;
    470 	}
    471 
    472 	if (va.va_size == 0) {
    473 		struct lr_alloc lr;
    474 
    475 		/*
    476 		 * Write Header.
    477 		 */
    478 		create_buffer_header(&loghdr, &loghdr_len, &loghdr_free);
    479 		/*
    480 		 * Dummy up a lr_alloc struct for the write
    481 		 */
    482 		lr.next = lr.prev = &lr;
    483 		lr.lr_flags = 0;
    484 		lr.log_record = loghdr;
    485 		lr.size = loghdr_len;
    486 		lr.alloc_cache = NULL;
    487 		lr.exi = NULL;
    488 		lr.lb = NULL;
    489 
    490 		mutex_enter(&logfile->lf_lock);
    491 
    492 		error = nfslog_write_logrecords(logfile, &lr, 1);
    493 
    494 		mutex_exit(&logfile->lf_lock);
    495 
    496 		if (error != 0) {
    497 			nfs_cmn_err(error, CE_WARN,
    498 			    "log_file_create: Can not write header "
    499 			    "on %s - error = %m", name);
    500 			goto out;
    501 		}
    502 	}
    503 	*lfpp = logfile;
    504 
    505 	if (loghdr != NULL)
    506 		kmem_free(loghdr, loghdr_free);
    507 
    508 	return (0);
    509 
    510 out:
    511 	if (vp != NULL) {
    512 		int error1;
    513 		error1 = VOP_CLOSE(vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
    514 		    CRED(), NULL);
    515 		if (error1) {
    516 			nfs_cmn_err(error1, CE_WARN,
    517 			    "log_file_create: Can not close %s - "
    518 			    "error = %m", name);
    519 		}
    520 		VN_RELE(vp);
    521 	}
    522 
    523 	kmem_free(name, namelen + 1);
    524 	if (logfile != NULL) {
    525 		mutex_destroy(&logfile->lf_lock);
    526 		kmem_free(logfile, sizeof (*logfile));
    527 		rfsl_log_file--;
    528 	}
    529 	if (loghdr != NULL)
    530 		kmem_free(loghdr, loghdr_free);
    531 
    532 	return (error);
    533 }
    534 
    535 /*
    536  * Release a log_file structure
    537  */
    538 static void
    539 log_file_rele(struct log_file *lfp)
    540 {
    541 	int len;
    542 	int error;
    543 
    544 	mutex_enter(&lfp->lf_lock);
    545 	if (--lfp->lf_refcnt > 0) {
    546 		LOGGING_DPRINT((10,
    547 		    "log_file_rele lfp=%p decremented refcnt to %d\n",
    548 		    (void *)lfp, lfp->lf_refcnt));
    549 		mutex_exit(&lfp->lf_lock);
    550 		return;
    551 	}
    552 	if (lfp->lf_refcnt < 0) {
    553 		panic("log_file_rele: log_file refcnt < 0");
    554 		/*NOTREACHED*/
    555 	}
    556 
    557 	LOGGING_DPRINT((10, "log_file_rele lfp=%p freeing node\n",
    558 	    (void *)lfp));
    559 
    560 	lfp->lf_flags &= ~(L_PRINTED | L_ERROR);
    561 
    562 	ASSERT(lfp->lf_flags == 0);
    563 	ASSERT(lfp->lf_writers == 0);
    564 
    565 	if (error = VOP_CLOSE(lfp->lf_vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
    566 	    CRED(), NULL)) {
    567 		nfs_cmn_err(error, CE_WARN,
    568 		    "NFS: Could not close log buffer %s - error = %m",
    569 		    lfp->lf_path);
    570 #ifdef DEBUG
    571 	} else {
    572 		LOGGING_DPRINT((3,
    573 		    "log_file_rele: %s has been closed vp=%p v_count=%d\n",
    574 		    lfp->lf_path, (void *)lfp->lf_vp, lfp->lf_vp->v_count));
    575 #endif
    576 	}
    577 	VN_RELE(lfp->lf_vp);
    578 
    579 	len = strlen(lfp->lf_path) + 1;
    580 	kmem_free(lfp->lf_path, len);
    581 	kmem_free(lfp, sizeof (*lfp));
    582 	rfsl_log_file--;
    583 }
    584 
    585 /*
    586  * Allocates a record of the size specified.
    587  * 'exi' identifies the exportinfo structure being logged.
    588  * 'size' indicates how much memory should be allocated
    589  * 'cookie' is used to store an opaque value for the caller for later use
    590  * 'flags' currently ignored.
    591  *
    592  * Returns a pointer to the beginning of the allocated memory.
    593  * 'cookie' is a pointer to the 'lr_alloc' struct; this will be used
    594  * to keep track of the encoded record and contains all the info
    595  * for enqueuing the record on the log buffer for later writing.
    596  *
    597  * nfslog_record_put() must be used to 'free' this record or allocation.
    598  */
    599 /* ARGSUSED */
    600 void *
    601 nfslog_record_alloc(
    602 	struct exportinfo *exi,
    603 	int alloc_indx,
    604 	void **cookie,
    605 	int flags)
    606 {
    607 	struct lr_alloc *lrp;
    608 
    609 	lrp = (struct lr_alloc *)
    610 	    kmem_cache_alloc(nfslog_mem_alloc[alloc_indx].mem_cache,
    611 	    KM_NOSLEEP);
    612 
    613 	if (lrp == NULL) {
    614 		*cookie = NULL;
    615 		return (NULL);
    616 	}
    617 
    618 	lrp->next = lrp;
    619 	lrp->prev = lrp;
    620 	lrp->lr_flags = 0;
    621 
    622 	lrp->log_record = (caddr_t)((uintptr_t)lrp +
    623 	    (uintptr_t)sizeof (struct lr_alloc));
    624 	lrp->size = nfslog_mem_alloc[alloc_indx].size;
    625 	lrp->alloc_cache = nfslog_mem_alloc[alloc_indx].mem_cache;
    626 	lrp->exi = exi;
    627 
    628 	if (exi->exi_export.ex_flags & EX_LOG) {
    629 		LOG_BUFFER_HOLD(exi->exi_logbuffer);
    630 		lrp->lb = exi->exi_logbuffer;
    631 	} else {
    632 		lrp->lb = NULL;
    633 	}
    634 
    635 	*cookie = (void *)lrp;
    636 
    637 	LOGGING_DPRINT((3,
    638 	    "nfslog_record_alloc(log_buffer=%p mem=%p size=%lu)\n",
    639 	    (void *)exi->exi_logbuffer, (void *)lrp->log_record, lrp->size));
    640 	return (lrp->log_record);
    641 }
    642 
    643 /*
    644  * After the above nfslog_record_alloc() has been called and a record
    645  * encoded into the buffer that was returned, this function is called
    646  * to handle appropriate disposition of the newly created record.
    647  * The cookie value is the one that was returned from nfslog_record_alloc().
    648  * Size is the actual size of the record that was encoded.  This is
    649  * passed in because the size used for the alloc was just an approximation.
    650  * The sync parameter is used to tell us if we need to force this record
    651  * to disk and if not it will be queued for later writing.
    652  *
    653  * Note that if the size parameter has a value of 0, then the record is
    654  * not written to the log and the associated data structures are released.
    655  */
    656 void
    657 nfslog_record_put(void *cookie, size_t size, bool_t sync,
    658 	unsigned int which_buffers)
    659 {
    660 	struct lr_alloc *lrp = (struct lr_alloc *)cookie;
    661 	struct log_buffer *lbp = lrp->lb;
    662 
    663 	/*
    664 	 * If the caller has nothing to write or if there is
    665 	 * an apparent error, rele the buffer and free.
    666 	 */
    667 	if (size == 0 || size > lrp->size) {
    668 		nfslog_free_logrecords(lrp);
    669 		return;
    670 	}
    671 
    672 	/*
    673 	 * Reset the size to what actually needs to be written
    674 	 * This is used later on when the iovec is built for
    675 	 * writing the records to the log file.
    676 	 */
    677 	lrp->size = size;
    678 
    679 	/* append to all if public exi */
    680 	if (which_buffers == NFSLOG_ALL_BUFFERS) {
    681 		(void) nfslog_record_append2all(lrp);
    682 		nfslog_free_logrecords(lrp);
    683 		return;
    684 	}
    685 
    686 	/* Insert the record on the list to be written */
    687 	mutex_enter(&lbp->lb_lock);
    688 	if (lbp->lb_records == NULL) {
    689 		lbp->lb_records = (caddr_t)lrp;
    690 		lbp->lb_num_recs = 1;
    691 		lbp->lb_size_queued = lrp->size;
    692 	} else {
    693 		insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev);
    694 		lbp->lb_num_recs++;
    695 		lbp->lb_size_queued += lrp->size;
    696 	}
    697 
    698 	/*
    699 	 * Determine if the queue for this log buffer should be flushed.
    700 	 * This is done by either the number of records queued, the total
    701 	 * size of all records queued or by the request of the caller
    702 	 * via the sync parameter.
    703 	 */
    704 	if (lbp->lb_size_queued >= nfslog_num_bytes_to_write ||
    705 	    lbp->lb_num_recs > nfslog_num_records_to_write || sync == TRUE) {
    706 		mutex_exit(&lbp->lb_lock);
    707 		(void) nfslog_records_flush_to_disk(lbp);
    708 	} else {
    709 		mutex_exit(&lbp->lb_lock);
    710 	}
    711 
    712 }
    713 
    714 /*
    715  * Examine the log_buffer struct to see if there are queue log records
    716  * that need to be written to disk.  If some exist, pull them off of
    717  * the log buffer and write them to the log file.
    718  */
    719 static int
    720 nfslog_records_flush_to_disk(struct log_buffer *lbp)
    721 {
    722 
    723 	mutex_enter(&lbp->lb_lock);
    724 
    725 	if (lbp->lb_records == NULL) {
    726 		mutex_exit(&lbp->lb_lock);
    727 		return (0);
    728 	}
    729 	return	(nfslog_records_flush_to_disk_nolock(lbp));
    730 }
    731 
    732 /*
    733  * Function requires that the caller holds lb_lock.
    734  * Function flushes any records in the log buffer to the disk.
    735  * Function drops the lb_lock on return.
    736  */
    737 
    738 static int
    739 nfslog_records_flush_to_disk_nolock(struct log_buffer *lbp)
    740 {
    741 	struct log_file *lfp = NULL;
    742 	struct lr_alloc *lrp_writers;
    743 	int num_recs;
    744 	int error = 0;
    745 
    746 	ASSERT(MUTEX_HELD(&lbp->lb_lock));
    747 
    748 	lfp = lbp->lb_logfile;
    749 
    750 	LOG_FILE_LOCK_TO_WRITE(lfp);
    751 	ASSERT(lbp->lb_records != NULL);
    752 
    753 	lrp_writers = (struct lr_alloc *)lbp->lb_records;
    754 	lbp->lb_records = NULL;
    755 	num_recs = lbp->lb_num_recs;
    756 	lbp->lb_num_recs = 0;
    757 	lbp->lb_size_queued = 0;
    758 	mutex_exit(&lbp->lb_lock);
    759 	error = nfslog_write_logrecords(lfp, lrp_writers, num_recs);
    760 
    761 	LOG_FILE_UNLOCK_FROM_WRITE(lfp);
    762 
    763 	nfslog_free_logrecords(lrp_writers);
    764 	return (error);
    765 }
    766 
    767 
    768 /*
    769  * Take care of writing the provided log record(s) to the log file.
    770  * We group the log records with an iovec and use VOP_WRITE to append
    771  * them to the end of the log file.
    772  */
    773 static int
    774 nfslog_write_logrecords(struct log_file *lfp,
    775 	struct lr_alloc *lrp_writers, int num_recs)
    776 {
    777 	struct uio uio;
    778 	struct iovec *iovp;
    779 	int size_iovecs;
    780 	vnode_t *vp;
    781 	struct vattr va;
    782 	struct lr_alloc *lrp;
    783 	int i;
    784 	ssize_t len;
    785 	int ioflag = FAPPEND;
    786 	int error = 0;
    787 
    788 	ASSERT(MUTEX_HELD(&lfp->lf_lock));
    789 
    790 	vp = lfp->lf_vp;
    791 
    792 	size_iovecs = sizeof (struct iovec) * num_recs;
    793 	iovp = (struct iovec *)kmem_alloc(size_iovecs, KM_NOSLEEP);
    794 
    795 	if (iovp == NULL) {
    796 		error = ENOMEM;
    797 		goto out;
    798 	}
    799 
    800 	/* Build the iovec based on the list of log records */
    801 	i = 0;
    802 	len = 0;
    803 	lrp = lrp_writers;
    804 	do {
    805 		iovp[i].iov_base = lrp->log_record;
    806 		iovp[i].iov_len = lrp->size;
    807 		len += lrp->size;
    808 		lrp = lrp->next;
    809 		i++;
    810 	} while (lrp != lrp_writers);
    811 
    812 	ASSERT(i == num_recs);
    813 
    814 	uio.uio_iov = iovp;
    815 	uio.uio_iovcnt = num_recs;
    816 	uio.uio_loffset = 0;
    817 	uio.uio_segflg = (short)UIO_SYSSPACE;
    818 	uio.uio_resid = len;
    819 	uio.uio_llimit = (rlim64_t)MAXOFFSET_T;
    820 	uio.uio_fmode = FWRITE;
    821 	uio.uio_extflg = UIO_COPY_DEFAULT;
    822 
    823 	/*
    824 	 * Save the size. If the write fails, reset the size to avoid
    825 	 * corrupted log buffer files.
    826 	 */
    827 	va.va_mask = AT_SIZE;
    828 
    829 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);  /* UIO_WRITE */
    830 	if ((error = VOP_GETATTR(vp, &va, 0, CRED(), NULL)) == 0) {
    831 		if ((len + va.va_size) < (MAXOFF32_T)) {
    832 			error = VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
    833 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
    834 			if (uio.uio_resid)
    835 				error = ENOSPC;
    836 			if (error)
    837 				(void) VOP_SETATTR(vp, &va, 0, CRED(), NULL);
    838 		} else {
    839 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
    840 			if (!(lfp->lf_flags & L_PRINTED)) {
    841 				cmn_err(CE_WARN,
    842 				    "NFS Logging: buffer file %s exceeds 2GB; "
    843 				    "stopped writing buffer \n", lfp->lf_path);
    844 			}
    845 			error = ENOSPC;
    846 		}
    847 	} else {
    848 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
    849 	}
    850 
    851 	kmem_free(iovp, size_iovecs);
    852 
    853 out:
    854 	if (error) {
    855 		if (!(lfp->lf_flags & L_PRINTED)) {
    856 			nfs_cmn_err(error, CE_WARN,
    857 			    "NFS Logging disabled for buffer %s - "
    858 			    "write error = %m\n", lfp->lf_path);
    859 			lfp->lf_flags |= L_PRINTED;
    860 		}
    861 	} else if (lfp->lf_flags & (L_ERROR | L_PRINTED)) {
    862 		lfp->lf_flags &= ~(L_ERROR | L_PRINTED);
    863 		cmn_err(CE_WARN,
    864 		    "NFS Logging re-enabled for buffer %s\n", lfp->lf_path);
    865 	}
    866 
    867 	return (error);
    868 }
    869 
    870 static void
    871 nfslog_free_logrecords(struct lr_alloc *lrp_writers)
    872 {
    873 	struct lr_alloc *lrp = lrp_writers;
    874 	struct lr_alloc *lrp_free;
    875 
    876 	do {
    877 		lrp_free = lrp;
    878 
    879 		lrp = lrp->next;
    880 
    881 		/*
    882 		 * Check to see if we are supposed to free this structure
    883 		 * and relese the log_buffer ref count.
    884 		 * It may be the case that the caller does not want this
    885 		 * structure and its record contents freed just yet.
    886 		 */
    887 		if ((lrp_free->lr_flags & LR_ALLOC_NOFREE) == 0) {
    888 			if (lrp_free->lb != NULL)
    889 				log_buffer_rele(lrp_free->lb);
    890 			if (lrp_free->alloc_cache) /* double check */
    891 				kmem_cache_free(lrp_free->alloc_cache,
    892 				    (void *)lrp_free);
    893 		} else {
    894 			/*
    895 			 * after being pulled from the list the
    896 			 * pointers need to be reinitialized.
    897 			 */
    898 			lrp_free->next = lrp_free;
    899 			lrp_free->prev = lrp_free;
    900 		}
    901 
    902 	} while (lrp != lrp_writers);
    903 }
    904 
    905 /*
    906  * Rename lbp->lb_logfile to reflect the true name requested by 'share'
    907  */
    908 static int
    909 nfslog_logbuffer_rename(struct log_buffer *lbp)
    910 {
    911 	struct log_file *lf;
    912 	int error;
    913 	struct log_file *logfile;
    914 
    915 	/*
    916 	 * Try our best to get the cache records into the log file
    917 	 * before the rename occurs.
    918 	 */
    919 	(void) nfslog_records_flush_to_disk(lbp);
    920 
    921 	/*
    922 	 * Hold lb_lock before retrieving
    923 	 * lb_logfile.
    924 	 * Hold a reference to the
    925 	 * "lf" structure. this is
    926 	 * same as LOG_FILE_HOLD()
    927 	 */
    928 	mutex_enter(&(lbp)->lb_lock);
    929 	lf = lbp->lb_logfile;
    930 	mutex_enter(&(lf)->lf_lock);
    931 	mutex_exit(&(lbp)->lb_lock);
    932 	lf->lf_refcnt++;
    933 	mutex_exit(&(lf)->lf_lock);
    934 
    935 	LOGGING_DPRINT((10, "nfslog_logbuffer_rename: renaming %s to %s\n",
    936 	    lf->lf_path, lbp->lb_path));
    937 
    938 	/*
    939 	 * rename the current buffer to what the daemon expects
    940 	 */
    941 	if (error = nfslog_logfile_rename(lf->lf_path, lbp->lb_path))
    942 		goto out;
    943 
    944 	/*
    945 	 * Create a new working buffer file and have all new data sent there.
    946 	 */
    947 	if (error = log_file_create(lbp->lb_path, &logfile)) {
    948 		/* Attempt to rename to original */
    949 		(void) nfslog_logfile_rename(lbp->lb_path, lf->lf_path);
    950 		goto out;
    951 	}
    952 
    953 	/*
    954 	 * Hold the lb_lock here, this will make
    955 	 * all the threads trying to access lb->logfile block
    956 	 * and get a new logfile structure instead of old one.
    957 	 */
    958 	mutex_enter(&(lbp)->lb_lock);
    959 	lbp->lb_logfile = logfile;
    960 	mutex_exit(&(lbp)->lb_lock);
    961 
    962 	LOG_FILE_RELE(lf);	/* release log_buffer's reference */
    963 
    964 	/*
    965 	 * Wait for log_file to be in a quiescent state before we
    966 	 * return to our caller to let it proceed with the reading of
    967 	 * this file.
    968 	 */
    969 	nfslog_logfile_wait(lf);
    970 
    971 out:
    972 	/*
    973 	 * Release our reference on "lf" in two different cases.
    974 	 * 1. Error condition, release only the reference
    975 	 *    that we held at the begining of this
    976 	 *    routine on "lf" structure.
    977 	 * 2. Fall through condition, no errors but the old
    978 	 *    logfile structure "lf" has been replaced with
    979 	 *    the new "logfile" structure, so release the
    980 	 *    reference that was part of the creation of
    981 	 *    "lf" structure to free up the resources.
    982 	 */
    983 
    984 	LOG_FILE_RELE(lf);
    985 
    986 	return (error);
    987 }
    988 
    989 /*
    990  * Renames the 'from' file to 'new'.
    991  */
    992 static int
    993 nfslog_logfile_rename(char *from, char *new)
    994 {
    995 	int error;
    996 
    997 	if (error = vn_rename(from, new, UIO_SYSSPACE)) {
    998 		cmn_err(CE_WARN,
    999 		    "nfslog_logfile_rename: couldn't rename %s to %s\n",
   1000 		    from, new);
   1001 	}
   1002 	return (error);
   1003 }
   1004 
   1005 /*
   1006  * Wait for the log_file writers to finish before returning
   1007  */
   1008 static void
   1009 nfslog_logfile_wait(struct log_file *lf)
   1010 {
   1011 	mutex_enter(&lf->lf_lock);
   1012 	while (lf->lf_writers > 0) {
   1013 		lf->lf_flags |= L_WAITING;
   1014 		(void) cv_wait_sig(&lf->lf_cv_waiters, &lf->lf_lock);
   1015 	}
   1016 	mutex_exit(&lf->lf_lock);
   1017 }
   1018 
   1019 static int
   1020 nfslog_record_append2all(struct lr_alloc *lrp)
   1021 {
   1022 	struct log_buffer *lbp, *nlbp;
   1023 	int error, ret_error = 0;
   1024 	int lr_flags = lrp->lr_flags;
   1025 
   1026 	rw_enter(&nfslog_buffer_list_lock, RW_READER);
   1027 	if ((lbp = nfslog_buffer_list) != NULL)
   1028 		LOG_BUFFER_HOLD(lbp);
   1029 	for (nlbp = NULL; lbp != NULL; lbp = nlbp) {
   1030 		if ((nlbp = lbp->lb_next) != NULL) {
   1031 			/*
   1032 			 * Remember next element in the list
   1033 			 */
   1034 			LOG_BUFFER_HOLD(nlbp);
   1035 		}
   1036 		rw_exit(&nfslog_buffer_list_lock);
   1037 
   1038 		/*
   1039 		 * Insert the record on the buffer's list to be written
   1040 		 * and then flush the records to the log file.
   1041 		 * Make sure to set the no free flag so that the
   1042 		 * record can be used for the next write
   1043 		 */
   1044 		lrp->lr_flags = LR_ALLOC_NOFREE;
   1045 
   1046 		ASSERT(lbp != NULL);
   1047 		mutex_enter(&lbp->lb_lock);
   1048 		if (lbp->lb_records == NULL) {
   1049 			lbp->lb_records = (caddr_t)lrp;
   1050 			lbp->lb_num_recs = 1;
   1051 			lbp->lb_size_queued = lrp->size;
   1052 		} else {
   1053 			insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev);
   1054 			lbp->lb_num_recs++;
   1055 			lbp->lb_size_queued += lrp->size;
   1056 		}
   1057 
   1058 		/*
   1059 		 * Flush log records to disk.
   1060 		 * Function is called with lb_lock held.
   1061 		 * Function drops the lb_lock on return.
   1062 		 */
   1063 		error = nfslog_records_flush_to_disk_nolock(lbp);
   1064 
   1065 		if (error) {
   1066 			ret_error = -1;
   1067 			nfs_cmn_err(error, CE_WARN,
   1068 			    "rfsl_log_pubfh: could not append record to "
   1069 			    "\"%s\" error = %m\n", lbp->lb_path);
   1070 		}
   1071 		log_buffer_rele(lbp);
   1072 		rw_enter(&nfslog_buffer_list_lock, RW_READER);
   1073 	}
   1074 	rw_exit(&nfslog_buffer_list_lock);
   1075 
   1076 	lrp->lr_flags = lr_flags;
   1077 
   1078 	return (ret_error);
   1079 }
   1080 
   1081 #ifdef DEBUG
   1082 static int logging_debug = 0;
   1083 
   1084 /*
   1085  * 0) no debugging
   1086  * 3) current test software
   1087  * 10) random stuff
   1088  */
   1089 void
   1090 nfslog_dprint(const int level, const char *fmt, ...)
   1091 {
   1092 	va_list args;
   1093 
   1094 	if (logging_debug == level ||
   1095 	    (logging_debug > 10 && (logging_debug - 10) >= level)) {
   1096 		va_start(args, fmt);
   1097 		(void) vprintf(fmt, args);
   1098 		va_end(args);
   1099 	}
   1100 }
   1101 
   1102 #endif /* DEBUG */
   1103 
   1104 /*
   1105  * NFS Log Flush system call
   1106  * Caller must check privileges.
   1107  */
   1108 /* ARGSUSED */
   1109 int
   1110 nfsl_flush(struct nfsl_flush_args *args, model_t model)
   1111 {
   1112 	struct flush_thread_params *tparams;
   1113 	struct nfsl_flush_args *nfsl_args;
   1114 	int error = 0;
   1115 	ulong_t buffer_len;
   1116 	STRUCT_HANDLE(nfsl_flush_args, uap);
   1117 
   1118 	STRUCT_SET_HANDLE(uap, model, args);
   1119 
   1120 	tparams = (struct flush_thread_params *)
   1121 	    kmem_zalloc(sizeof (*tparams), KM_SLEEP);
   1122 
   1123 	nfsl_args = &tparams->tp_args;
   1124 	nfsl_args->version =  STRUCT_FGET(uap, version);
   1125 	if (nfsl_args->version != NFSL_FLUSH_ARGS_VERS) {
   1126 		cmn_err(CE_WARN, "nfsl_flush: exected version %d, got %d",
   1127 		    NFSL_FLUSH_ARGS_VERS, nfsl_args->version);
   1128 		return (EIO);
   1129 	}
   1130 
   1131 	nfsl_args->directive = STRUCT_FGET(uap, directive);
   1132 	if ((nfsl_args->directive & NFSL_ALL) == 0) {
   1133 		/*
   1134 		 * Process a specific buffer
   1135 		 */
   1136 		nfsl_args->buff_len = STRUCT_FGET(uap, buff_len);
   1137 
   1138 		nfsl_args->buff = (char *)
   1139 		    kmem_alloc(nfsl_args->buff_len, KM_NOSLEEP);
   1140 		if (nfsl_args->buff == NULL)
   1141 			return (ENOMEM);
   1142 
   1143 		error = copyinstr((const char *)STRUCT_FGETP(uap, buff),
   1144 		    nfsl_args->buff, nfsl_args->buff_len, &buffer_len);
   1145 		if (error)
   1146 			return (EFAULT);
   1147 
   1148 		if (nfsl_args->buff_len != buffer_len)
   1149 			return (EFAULT);
   1150 	}
   1151 
   1152 	LOGGING_DPRINT((10, "nfsl_flush: Flushing %s buffer(s)\n",
   1153 	    nfsl_args->directive & NFSL_ALL ? "all" : nfsl_args->buff));
   1154 
   1155 	if (nfsl_args->directive & NFSL_SYNC) {
   1156 		/*
   1157 		 * Do the work synchronously
   1158 		 */
   1159 		nfslog_do_flush(tparams);
   1160 		error = tparams->tp_error;
   1161 		kmem_free(nfsl_args->buff, nfsl_args->buff_len);
   1162 		kmem_free(tparams, sizeof (*tparams));
   1163 	} else {
   1164 		/*
   1165 		 * Do the work asynchronously
   1166 		 */
   1167 		(void) thread_create(NULL, 0, nfslog_do_flush,
   1168 		    tparams, 0, &p0, TS_RUN, minclsyspri);
   1169 	}
   1170 
   1171 	return (error);
   1172 }
   1173 
   1174 /*
   1175  * This is where buffer flushing would occur, but there is no buffering
   1176  * at this time.
   1177  * Possibly rename the log buffer for processing.
   1178  * Sets tparams->ta_error equal to the value of the error that occurred,
   1179  * 0 otherwise.
   1180  * Returns ENOENT if the buffer is not found.
   1181  */
   1182 static void
   1183 nfslog_do_flush(struct flush_thread_params *tparams)
   1184 {
   1185 	struct nfsl_flush_args *args;
   1186 	struct log_buffer *lbp, *nlbp;
   1187 	int error = ENOENT;
   1188 	int found = 0;
   1189 	char *buf_inprog;	/* name of buff in progress */
   1190 	int buf_inprog_len;
   1191 
   1192 	/*
   1193 	 * Sanity check on the arguments.
   1194 	 */
   1195 	if (!tparams)
   1196 		return;
   1197 	args = &tparams->tp_args;
   1198 	if (!args)
   1199 		return;
   1200 
   1201 	rw_enter(&nfslog_buffer_list_lock, RW_READER);
   1202 	if ((lbp = nfslog_buffer_list) != NULL) {
   1203 		LOG_BUFFER_HOLD(lbp);
   1204 	}
   1205 	for (nlbp = NULL; lbp != NULL; lbp = nlbp) {
   1206 		if ((nlbp = lbp->lb_next) != NULL) {
   1207 			LOG_BUFFER_HOLD(nlbp);
   1208 		}
   1209 		rw_exit(&nfslog_buffer_list_lock);
   1210 		if (args->directive & NFSL_ALL) {
   1211 			(void) nfslog_records_flush_to_disk(lbp);
   1212 		} else {
   1213 			if ((strcmp(lbp->lb_path, args->buff) == 0) &&
   1214 			    (args->directive & NFSL_RENAME)) {
   1215 				error = nfslog_logbuffer_rename(lbp);
   1216 				found++;
   1217 				if (nlbp != NULL)
   1218 					log_buffer_rele(nlbp);
   1219 				log_buffer_rele(lbp);
   1220 				break;
   1221 			}
   1222 		}
   1223 		log_buffer_rele(lbp);
   1224 		rw_enter(&nfslog_buffer_list_lock, RW_READER);
   1225 	}
   1226 	if (!found)
   1227 		rw_exit(&nfslog_buffer_list_lock);
   1228 
   1229 	if (!found && ((args->directive & NFSL_ALL) == 0) &&
   1230 	    (args->directive & NFSL_RENAME)) {
   1231 		/*
   1232 		 * The specified buffer is not currently in use,
   1233 		 * simply rename the file indicated.
   1234 		 */
   1235 		buf_inprog_len = strlen(args->buff) +
   1236 		    strlen(LOG_INPROG_STRING) + 1;
   1237 		buf_inprog = (caddr_t)kmem_alloc(buf_inprog_len, KM_SLEEP);
   1238 		(void) sprintf(buf_inprog, "%s%s",
   1239 		    args->buff, LOG_INPROG_STRING);
   1240 
   1241 		error = nfslog_logfile_rename(buf_inprog, args->buff);
   1242 
   1243 		kmem_free(buf_inprog, buf_inprog_len);
   1244 	}
   1245 
   1246 out:
   1247 	if ((args->directive & NFSL_SYNC) == 0) {
   1248 		/*
   1249 		 * Work was performed asynchronously, the caller is
   1250 		 * no longer waiting for us.
   1251 		 * Free the thread arguments and exit.
   1252 		 */
   1253 		kmem_free(args->buff, args->buff_len);
   1254 		kmem_free(tparams, sizeof (*tparams));
   1255 		thread_exit();
   1256 		/* NOTREACHED */
   1257 	}
   1258 
   1259 	tparams->tp_error = error;
   1260 }
   1261 
   1262 /*
   1263  * Generate buffer_header.
   1264  * 'loghdr' points the the buffer_header, and *reclen
   1265  * contains the length of the buffer.
   1266  */
   1267 static void
   1268 create_buffer_header(caddr_t *loghdr, size_t *reclen, size_t *freesize)
   1269 {
   1270 	timestruc_t		now;
   1271 	nfslog_buffer_header	lh;
   1272 	XDR			xdrs;
   1273 	unsigned int		final_size;
   1274 
   1275 
   1276 	/* pick some size that will hold the buffer_header */
   1277 	*freesize = NFSLOG_SMALL_RECORD_SIZE;
   1278 
   1279 	/*
   1280 	 * Fill header
   1281 	 */
   1282 	lh.bh_length = 0;	/* don't know yet how large it will be */
   1283 	lh.bh_version = NFSLOG_BUF_VERSION;
   1284 	lh.bh_flags = 0;
   1285 	lh.bh_offset = 0;
   1286 	gethrestime(&now);
   1287 	TIMESPEC_TO_TIMESPEC32(&lh.bh_timestamp, &now);
   1288 
   1289 	/*
   1290 	 * Encode the header
   1291 	 */
   1292 	*loghdr = (caddr_t)kmem_alloc(*freesize, KM_SLEEP);
   1293 	xdrmem_create(&xdrs, *loghdr, *freesize, XDR_ENCODE);
   1294 
   1295 	(void) xdr_nfslog_buffer_header(&xdrs, &lh);
   1296 
   1297 	/*
   1298 	 * Reset with final size of the encoded data
   1299 	 */
   1300 	final_size = xdr_getpos(&xdrs);
   1301 	xdr_setpos(&xdrs, 0);
   1302 	(void) xdr_u_int(&xdrs, &final_size);
   1303 
   1304 	*reclen = (size_t)final_size;
   1305 }
   1306 
   1307 /*
   1308  * ****************************************************************
   1309  * RPC dispatch table for logging
   1310  * Indexed by program, version, proc
   1311  * Based on NFS dispatch table.
   1312  */
   1313 struct nfslog_proc_disp {
   1314 	bool_t	(*xdrargs)();
   1315 	bool_t	(*xdrres)();
   1316 	bool_t	affects_transactions;	/* Operation affects transaction */
   1317 					/* processing */
   1318 };
   1319 
   1320 struct nfslog_vers_disp {
   1321 	int	nfslog_dis_nprocs;			/* number of procs */
   1322 	struct nfslog_proc_disp	*nfslog_dis_proc_table;	/* proc array */
   1323 };
   1324 
   1325 struct nfslog_prog_disp {
   1326 	int	nfslog_dis_prog;		/* program number */
   1327 	int	nfslog_dis_versmin;		/* Minimum version value */
   1328 	int	nfslog_dis_nvers;		/* Number of version values */
   1329 	struct nfslog_vers_disp	*nfslog_dis_vers_table;	/* versions array */
   1330 };
   1331 
   1332 static int rfs_log_bad = 0;	/* incremented on bad log attempts */
   1333 static int rfs_log_good = 0;	/* incremented on successful log attempts */
   1334 
   1335 /*
   1336  * Define the actions taken per prog/vers/proc:
   1337  *
   1338  * In some cases, the nl types are the same as the nfs types and a simple
   1339  * bcopy should suffice. Rather that define tens of identical procedures,
   1340  * simply define these to bcopy. Similarly this takes care of different
   1341  * procs that use same parameter struct.
   1342  */
   1343 
   1344 static struct nfslog_proc_disp nfslog_proc_v2[] = {
   1345 	/*
   1346 	 * NFS VERSION 2
   1347 	 */
   1348 
   1349 	/* RFS_NULL = 0 */
   1350 	{xdr_void, xdr_void, FALSE},
   1351 
   1352 	/* RFS_GETATTR = 1 */
   1353 	{xdr_fhandle, xdr_nfslog_getattrres, FALSE},
   1354 
   1355 	/* RFS_SETATTR = 2 */
   1356 	{xdr_nfslog_setattrargs, xdr_nfsstat, TRUE},
   1357 
   1358 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
   1359 	{xdr_void, xdr_void, FALSE},
   1360 
   1361 	/* RFS_LOOKUP = 4 */
   1362 	{xdr_nfslog_diropargs, xdr_nfslog_diropres, TRUE},
   1363 
   1364 	/* RFS_READLINK = 5 */
   1365 	{xdr_fhandle, xdr_nfslog_rdlnres, FALSE},
   1366 
   1367 	/* RFS_READ = 6 */
   1368 	{xdr_nfslog_nfsreadargs, xdr_nfslog_rdresult, TRUE},
   1369 
   1370 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
   1371 	{xdr_void, xdr_void, FALSE},
   1372 
   1373 	/* RFS_WRITE = 8 */
   1374 	{xdr_nfslog_writeargs, xdr_nfslog_writeresult, TRUE},
   1375 
   1376 	/* RFS_CREATE = 9 */
   1377 	{xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE},
   1378 
   1379 	/* RFS_REMOVE = 10 */
   1380 	{xdr_nfslog_diropargs, xdr_nfsstat, TRUE},
   1381 
   1382 	/* RFS_RENAME = 11 */
   1383 	{xdr_nfslog_rnmargs, xdr_nfsstat, TRUE},
   1384 
   1385 	/* RFS_LINK = 12 */
   1386 	{xdr_nfslog_linkargs, xdr_nfsstat, TRUE},
   1387 
   1388 	/* RFS_SYMLINK = 13 */
   1389 	{xdr_nfslog_symlinkargs, xdr_nfsstat, TRUE},
   1390 
   1391 	/* RFS_MKDIR = 14 */
   1392 	{xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE},
   1393 
   1394 	/* RFS_RMDIR = 15 */
   1395 	{xdr_nfslog_diropargs, xdr_nfsstat, TRUE},
   1396 
   1397 	/* RFS_READDIR = 16 */
   1398 	{xdr_nfslog_rddirargs, xdr_nfslog_rddirres, TRUE},
   1399 
   1400 	/* RFS_STATFS = 17 */
   1401 	{xdr_fhandle, xdr_nfslog_statfs, FALSE},
   1402 };
   1403 
   1404 
   1405 /*
   1406  * NFS VERSION 3
   1407  */
   1408 
   1409 static struct nfslog_proc_disp nfslog_proc_v3[] = {
   1410 
   1411 	/* NFSPROC3_NULL = 0 */
   1412 	{xdr_void, xdr_void, FALSE},
   1413 
   1414 	/* NFSPROC3_GETATTR = 1 */
   1415 	{xdr_nfslog_nfs_fh3, xdr_nfslog_GETATTR3res, FALSE},
   1416 
   1417 	/* NFSPROC3_SETATTR = 2 */
   1418 	{xdr_nfslog_SETATTR3args, xdr_nfslog_SETATTR3res, TRUE},
   1419 
   1420 	/* NFSPROC3_LOOKUP = 3 */
   1421 	{xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE},
   1422 
   1423 	/* NFSPROC3_ACCESS = 4 */
   1424 	{xdr_nfslog_ACCESS3args, xdr_nfslog_ACCESS3res, FALSE},
   1425 
   1426 	/* NFSPROC3_READLINK = 5 */
   1427 	{xdr_nfslog_nfs_fh3, xdr_nfslog_READLINK3res, FALSE},
   1428 
   1429 	/* NFSPROC3_READ = 6 */
   1430 	{xdr_nfslog_READ3args, xdr_nfslog_READ3res, TRUE},
   1431 
   1432 	/* NFSPROC3_WRITE = 7 */
   1433 	{xdr_nfslog_WRITE3args, xdr_nfslog_WRITE3res, TRUE},
   1434 
   1435 	/* NFSPROC3_CREATE = 8 */
   1436 	{xdr_nfslog_CREATE3args, xdr_nfslog_CREATE3res, TRUE},
   1437 
   1438 	/* NFSPROC3_MKDIR = 9 */
   1439 	{xdr_nfslog_MKDIR3args, xdr_nfslog_MKDIR3res, TRUE},
   1440 
   1441 	/* NFSPROC3_SYMLINK = 10 */
   1442 	{xdr_nfslog_SYMLINK3args, xdr_nfslog_SYMLINK3res, TRUE},
   1443 
   1444 	/* NFSPROC3_MKNOD = 11 */
   1445 	{xdr_nfslog_MKNOD3args, xdr_nfslog_MKNOD3res, TRUE},
   1446 
   1447 	/* NFSPROC3_REMOVE = 12 */
   1448 	{xdr_nfslog_REMOVE3args, xdr_nfslog_REMOVE3res, TRUE},
   1449 
   1450 	/* NFSPROC3_RMDIR = 13 */
   1451 	{xdr_nfslog_RMDIR3args, xdr_nfslog_RMDIR3res, TRUE},
   1452 
   1453 	/* NFSPROC3_RENAME = 14 */
   1454 	{xdr_nfslog_RENAME3args, xdr_nfslog_RENAME3res, TRUE},
   1455 
   1456 	/* NFSPROC3_LINK = 15 */
   1457 	{xdr_nfslog_LINK3args, xdr_nfslog_LINK3res, TRUE},
   1458 
   1459 	/* NFSPROC3_READDIR = 16 */
   1460 	{xdr_nfslog_READDIR3args, xdr_nfslog_READDIR3res, TRUE},
   1461 
   1462 	/* NFSPROC3_READDIRPLUS = 17 */
   1463 	{xdr_nfslog_READDIRPLUS3args, xdr_nfslog_READDIRPLUS3res, TRUE},
   1464 
   1465 	/* NFSPROC3_FSSTAT = 18 */
   1466 	{xdr_nfslog_FSSTAT3args, xdr_nfslog_FSSTAT3res, FALSE},
   1467 
   1468 	/* NFSPROC3_FSINFO = 19 */
   1469 	{xdr_nfslog_FSINFO3args, xdr_nfslog_FSINFO3res, FALSE},
   1470 
   1471 	/* NFSPROC3_PATHCONF = 20 */
   1472 	{xdr_nfslog_PATHCONF3args, xdr_nfslog_PATHCONF3res, FALSE},
   1473 
   1474 	/* NFSPROC3_COMMIT = 21 */
   1475 	{xdr_nfslog_COMMIT3args, xdr_nfslog_COMMIT3res, FALSE},
   1476 };
   1477 
   1478 static struct nfslog_proc_disp nfslog_proc_v1[] = {
   1479 	/*
   1480 	 * NFSLOG VERSION 1
   1481 	 */
   1482 
   1483 	/* NFSLOG_NULL = 0 */
   1484 	{xdr_void, xdr_void, TRUE},
   1485 
   1486 	/* NFSLOG_SHARE = 1 */
   1487 	{xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE},
   1488 
   1489 	/* NFSLOG_UNSHARE = 2 */
   1490 	{xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE},
   1491 
   1492 	/* NFSLOG_LOOKUP = 3 */
   1493 	{xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE},
   1494 
   1495 	/* NFSLOG_GETFH = 4 */
   1496 	{xdr_nfslog_getfhargs, xdr_nfsstat, TRUE},
   1497 };
   1498 
   1499 static struct nfslog_vers_disp nfslog_vers_disptable[] = {
   1500 	{sizeof (nfslog_proc_v2) / sizeof (nfslog_proc_v2[0]),
   1501 	    nfslog_proc_v2},
   1502 	{sizeof (nfslog_proc_v3) / sizeof (nfslog_proc_v3[0]),
   1503 	    nfslog_proc_v3},
   1504 };
   1505 
   1506 static struct nfslog_vers_disp nfslog_nfslog_vers_disptable[] = {
   1507 	{sizeof (nfslog_proc_v1) / sizeof (nfslog_proc_v1[0]),
   1508 	    nfslog_proc_v1},
   1509 };
   1510 
   1511 static struct nfslog_prog_disp nfslog_dispatch_table[] = {
   1512 	{NFS_PROGRAM, NFS_VERSMIN,
   1513 		(sizeof (nfslog_vers_disptable) /
   1514 		sizeof (nfslog_vers_disptable[0])),
   1515 		nfslog_vers_disptable},
   1516 
   1517 	{NFSLOG_PROGRAM, NFSLOG_VERSMIN,
   1518 		(sizeof (nfslog_nfslog_vers_disptable) /
   1519 		sizeof (nfslog_nfslog_vers_disptable[0])),
   1520 		nfslog_nfslog_vers_disptable},
   1521 };
   1522 
   1523 static int	nfslog_dispatch_table_arglen = sizeof (nfslog_dispatch_table) /
   1524 					sizeof (nfslog_dispatch_table[0]);
   1525 
   1526 /*
   1527  * This function will determine the appropriate export info struct to use
   1528  * and allocate a record id to be used in the written log buffer.
   1529  * Usually this is a straightforward operation but the existence of the
   1530  * multicomponent lookup and its semantics of crossing file system
   1531  * boundaries add to the complexity.  See the comments below...
   1532  */
   1533 struct exportinfo *
   1534 nfslog_get_exi(
   1535 	struct exportinfo *exi,
   1536 	struct svc_req *req,
   1537 	caddr_t res,
   1538 	unsigned int *nfslog_rec_id)
   1539 {
   1540 	struct log_buffer *lb;
   1541 	struct exportinfo *exi_ret = NULL;
   1542 	fhandle_t		*fh;
   1543 	nfs_fh3			*fh3;
   1544 
   1545 	if (exi == NULL)
   1546 		return (NULL);
   1547 
   1548 	/*
   1549 	 * If the exi is marked for logging, allocate a record id and return
   1550 	 */
   1551 	if (exi->exi_export.ex_flags & EX_LOG) {
   1552 		lb = exi->exi_logbuffer;
   1553 
   1554 		/* obtain the unique record id for the caller */
   1555 		*nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1);
   1556 
   1557 		/*
   1558 		 * The caller will expect to be able to exi_rele() it,
   1559 		 * so exi->exi_count must be incremented before it can
   1560 		 * be returned, to make it uniform with exi_ret->exi_count
   1561 		 */
   1562 		mutex_enter(&exi->exi_lock);
   1563 		exi->exi_count++;
   1564 		mutex_exit(&exi->exi_lock);
   1565 
   1566 		return (exi);
   1567 	}
   1568 
   1569 	if (exi != exi_public)
   1570 		return (NULL);
   1571 
   1572 	/*
   1573 	 * Here we have an exi that is not marked for logging.
   1574 	 * It is possible that this request is a multicomponent lookup
   1575 	 * that was done from the public file handle (not logged) and
   1576 	 * the resulting file handle being returned to the client exists
   1577 	 * in a file system that is being logged.  If this is the case
   1578 	 * we need to log this multicomponent lookup to the appropriate
   1579 	 * log buffer.  This will allow for the appropriate path name
   1580 	 * mapping to occur at user level.
   1581 	 */
   1582 	if (req->rq_prog == NFS_PROGRAM) {
   1583 		switch (req->rq_vers) {
   1584 		case NFS_V3:
   1585 			if ((req->rq_proc == NFSPROC3_LOOKUP) &&
   1586 			    (((LOOKUP3res *)res)->status == NFS3_OK)) {
   1587 				fh3 = &((LOOKUP3res *)res)->res_u.ok.object;
   1588 				exi_ret = checkexport(&fh3->fh3_fsid,
   1589 				    FH3TOXFIDP(fh3));
   1590 			}
   1591 			break;
   1592 
   1593 		case NFS_VERSION:
   1594 			if ((req->rq_proc == RFS_LOOKUP) &&
   1595 			    (((struct nfsdiropres *)
   1596 			    res)->dr_status == NFS_OK)) {
   1597 				fh =  &((struct nfsdiropres *)res)->
   1598 				    dr_u.dr_drok_u.drok_fhandle;
   1599 				exi_ret = checkexport(&fh->fh_fsid,
   1600 				    (fid_t *)&fh->fh_xlen);
   1601 			}
   1602 			break;
   1603 		default:
   1604 			break;
   1605 		}
   1606 	}
   1607 
   1608 	if (exi_ret != NULL && exi_ret->exi_export.ex_flags & EX_LOG) {
   1609 		lb = exi_ret->exi_logbuffer;
   1610 		/* obtain the unique record id for the caller */
   1611 		*nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1);
   1612 
   1613 		return (exi_ret);
   1614 	}
   1615 	return (NULL);
   1616 }
   1617 
   1618 #ifdef DEBUG
   1619 static long long rfslog_records_ignored = 0;
   1620 #endif
   1621 
   1622 /*
   1623  * nfslog_write_record - Fill in the record buffer for writing out.
   1624  * If logrecp is null, log it, otherwise, malloc the record and return it.
   1625  *
   1626  * It is the responsibility of the caller to check whether this exportinfo
   1627  * has logging enabled.
   1628  * Note that nfslog_share_public_record() only needs to check for the
   1629  * existence of at least one logbuffer to which the public filehandle record
   1630  * needs to be logged.
   1631  */
   1632 void
   1633 nfslog_write_record(struct exportinfo *exi, struct svc_req *req,
   1634 	caddr_t args, caddr_t res, cred_t *cr, struct netbuf *pnb,
   1635 	unsigned int record_id, unsigned int which_buffers)
   1636 {
   1637 	struct nfslog_prog_disp	*progtable;	/* prog struct */
   1638 	struct nfslog_vers_disp	*verstable;	/* version struct */
   1639 	struct nfslog_proc_disp	*disp = NULL;	/* proc struct */
   1640 	int			i, vers;
   1641 	void			*log_cookie;	/* for logrecord if */
   1642 	caddr_t			buffer;
   1643 	XDR			xdrs;
   1644 	unsigned int		final_size;
   1645 	int			encode_ok;
   1646 	int			alloc_indx;
   1647 
   1648 	ASSERT(exi != NULL); ASSERT(req != NULL); ASSERT(args != NULL);
   1649 	ASSERT(res != NULL); ASSERT(cr != NULL);
   1650 
   1651 	/*
   1652 	 * Find program element
   1653 	 * Search the list since program can not be used as index
   1654 	 */
   1655 	for (i = 0; (i < nfslog_dispatch_table_arglen); i++) {
   1656 		if (req->rq_prog == nfslog_dispatch_table[i].nfslog_dis_prog)
   1657 			break;
   1658 	}
   1659 	if (i >= nfslog_dispatch_table_arglen) {	/* program not logged */
   1660 		/* not an error */
   1661 		return;
   1662 	}
   1663 
   1664 	/*
   1665 	 * Extract the dispatch functions based on program/version
   1666 	 */
   1667 	progtable = &nfslog_dispatch_table[i];
   1668 	vers = req->rq_vers - progtable->nfslog_dis_versmin;
   1669 	verstable = &progtable->nfslog_dis_vers_table[vers];
   1670 	disp = &verstable->nfslog_dis_proc_table[req->rq_proc];
   1671 
   1672 	if (!(exi->exi_export.ex_flags & EX_LOG_ALLOPS) &&
   1673 	    !disp->affects_transactions) {
   1674 		/*
   1675 		 * Only interested in logging operations affecting
   1676 		 * transaction generation. This is not one of them.
   1677 		 */
   1678 #ifdef DEBUG
   1679 		rfslog_records_ignored++;
   1680 #endif
   1681 		return;
   1682 	}
   1683 
   1684 	switch (req->rq_prog) {
   1685 	case NFS_PROGRAM:
   1686 		switch (req->rq_vers) {
   1687 		case NFS_V3:
   1688 			switch (req->rq_proc) {
   1689 			case NFSPROC3_READDIRPLUS:
   1690 				alloc_indx = MEDIUM_INDX;
   1691 				break;
   1692 			default:
   1693 				alloc_indx = SMALL_INDX;
   1694 				break;
   1695 			}
   1696 			break;
   1697 		default:
   1698 			alloc_indx = SMALL_INDX;
   1699 			break;
   1700 		}
   1701 		break;
   1702 	case NFSLOG_PROGRAM:
   1703 		alloc_indx = MEDIUM_INDX;
   1704 		break;
   1705 	default:
   1706 		alloc_indx = SMALL_INDX;
   1707 		break;
   1708 	}
   1709 
   1710 	do {
   1711 		encode_ok = FALSE;
   1712 
   1713 		/* Pick the size to alloc; end of the road - return */
   1714 		if (nfslog_mem_alloc[alloc_indx].size == (-1)) {
   1715 			cmn_err(CE_WARN,
   1716 			    "NFSLOG: unable to encode record - prog=%d "
   1717 			    "proc = %d", req->rq_prog, req->rq_proc);
   1718 			return;
   1719 		}
   1720 
   1721 		buffer = nfslog_record_alloc(exi, alloc_indx, &log_cookie, 0);
   1722 		if (buffer == NULL) {
   1723 			/* Error processing - no space alloced */
   1724 			rfs_log_bad++;
   1725 			cmn_err(CE_WARN, "NFSLOG: can't get record");
   1726 			return;
   1727 		}
   1728 
   1729 		xdrmem_create(&xdrs, buffer,
   1730 		    nfslog_mem_alloc[alloc_indx].size, XDR_ENCODE);
   1731 
   1732 		/*
   1733 		 * Encode the header, args and results of the record
   1734 		 */
   1735 		if (xdr_nfslog_request_record(&xdrs, exi, req, cr, pnb,
   1736 		    nfslog_mem_alloc[alloc_indx].size, record_id) &&
   1737 		    (*disp->xdrargs)(&xdrs, args) &&
   1738 		    (*disp->xdrres)(&xdrs, res)) {
   1739 				encode_ok = TRUE;
   1740 
   1741 				rfs_log_good++;
   1742 				/*
   1743 				 * Get the final size of the encoded
   1744 				 * data and insert that length at the
   1745 				 * beginning.
   1746 				 */
   1747 				final_size = xdr_getpos(&xdrs);
   1748 				xdr_setpos(&xdrs, 0);
   1749 				(void) xdr_u_int(&xdrs, &final_size);
   1750 		} else {
   1751 			/* Oops, the encode failed so we need to free memory */
   1752 			nfslog_record_put(log_cookie, 0, FALSE, which_buffers);
   1753 			alloc_indx++;
   1754 		}
   1755 
   1756 	} while (encode_ok == FALSE);
   1757 
   1758 
   1759 	/*
   1760 	 * Take the final log record and put it in the log file.
   1761 	 * This may be queued to the file internally and written
   1762 	 * later unless the last parameter is TRUE.
   1763 	 * If the record_id is 0 then this is most likely a share/unshare
   1764 	 * request and it should be written synchronously to the log file.
   1765 	 */
   1766 	nfslog_record_put(log_cookie,
   1767 	    final_size, (record_id == 0), which_buffers);
   1768 }
   1769 
   1770 static char *
   1771 get_publicfh_path(int *alloc_length)
   1772 {
   1773 	extern struct exportinfo *exi_public;
   1774 	char *pubpath;
   1775 
   1776 	rw_enter(&exported_lock, RW_READER);
   1777 
   1778 	*alloc_length = exi_public->exi_export.ex_pathlen + 1;
   1779 	pubpath = kmem_alloc(*alloc_length, KM_SLEEP);
   1780 
   1781 	(void) strcpy(pubpath, exi_public->exi_export.ex_path);
   1782 
   1783 	rw_exit(&exported_lock);
   1784 
   1785 	return (pubpath);
   1786 }
   1787 
   1788 static void
   1789 log_public_record(struct exportinfo *exi, cred_t *cr)
   1790 {
   1791 	struct svc_req	req;
   1792 	struct netbuf	nb = {0, 0, NULL};
   1793 	int free_length = 0;
   1794 	diropargs3 args;
   1795 	LOOKUP3res res;
   1796 
   1797 	bzero(&req, sizeof (req));
   1798 	req.rq_prog = NFSLOG_PROGRAM;
   1799 	req.rq_vers = NFSLOG_VERSION;
   1800 	req.rq_proc = NFSLOG_LOOKUP;
   1801 	req.rq_cred.oa_flavor = AUTH_NONE;
   1802 
   1803 	bzero(&args, sizeof (diropargs3));
   1804 	bzero(&res, sizeof (LOOKUP3res));
   1805 
   1806 	args.dir.fh3_length = 0;
   1807 	if ((args.name = get_publicfh_path(&free_length)) == NULL)
   1808 		return;
   1809 	args.dirp = &args.dir;
   1810 
   1811 	res.status = NFS3_OK;
   1812 	res.res_u.ok.object.fh3_length = 0;
   1813 
   1814 	/*
   1815 	 * Calling this function with the exi_public
   1816 	 * will have the effect of appending the record
   1817 	 * to each of the open log buffers
   1818 	 */
   1819 	nfslog_write_record(exi, &req,
   1820 	    (caddr_t)&args, (caddr_t)&res, cr, &nb, 0, NFSLOG_ALL_BUFFERS);
   1821 
   1822 	kmem_free(args.name, free_length);
   1823 }
   1824 
   1825 /*
   1826  * nfslog_share_record - logs a share request.
   1827  * This is not an NFS request, but we pretend here...
   1828  */
   1829 void
   1830 nfslog_share_record(struct exportinfo *exi, cred_t *cr)
   1831 {
   1832 	struct svc_req	req;
   1833 	int		res = 0;
   1834 	struct netbuf	nb = {0, 0, NULL};
   1835 
   1836 	ASSERT(exi != NULL);
   1837 
   1838 	if (nfslog_buffer_list == NULL)
   1839 		return;
   1840 
   1841 	if (exi->exi_export.ex_flags & EX_LOG) {
   1842 		bzero(&req, sizeof (req));
   1843 		req.rq_prog = NFSLOG_PROGRAM;
   1844 		req.rq_vers = NFSLOG_VERSION;
   1845 		req.rq_proc = NFSLOG_SHARE;
   1846 		req.rq_cred.oa_flavor = AUTH_NONE;
   1847 		nfslog_write_record(exi, &req, (caddr_t)exi, (caddr_t)&res, cr,
   1848 		    &nb, 0, NFSLOG_ONE_BUFFER);
   1849 	}
   1850 
   1851 	log_public_record(exi, cr);
   1852 }
   1853 
   1854 /*
   1855  * nfslog_unshare_record - logs an unshare request.
   1856  * This is not an NFS request, but we pretend here...
   1857  */
   1858 void
   1859 nfslog_unshare_record(struct exportinfo *exi, cred_t *cr)
   1860 {
   1861 	struct svc_req	req;
   1862 	int		res = 0;
   1863 	struct netbuf	nb = {0, 0, NULL};
   1864 
   1865 	ASSERT(exi != NULL);
   1866 	ASSERT(exi->exi_export.ex_flags & EX_LOG);
   1867 
   1868 	bzero(&req, sizeof (req));
   1869 	req.rq_prog = NFSLOG_PROGRAM;
   1870 	req.rq_vers = NFSLOG_VERSION;
   1871 	req.rq_proc = NFSLOG_UNSHARE;
   1872 	req.rq_cred.oa_flavor = AUTH_NONE;
   1873 	nfslog_write_record(exi, &req,
   1874 	    (caddr_t)exi, (caddr_t)&res, cr, &nb, 0, NFSLOG_ONE_BUFFER);
   1875 }
   1876 
   1877 
   1878 void
   1879 nfslog_getfh(struct exportinfo *exi,
   1880 	fhandle *fh,
   1881 	char *fname,
   1882 	enum uio_seg seg,
   1883 	cred_t *cr)
   1884 {
   1885 	struct svc_req	req;
   1886 	int		res = 0;
   1887 	struct netbuf	nb = {0, 0, NULL};
   1888 	int		error = 0;
   1889 	char		*namebuf;
   1890 	size_t		len;
   1891 	nfslog_getfhargs gfh;
   1892 
   1893 	ASSERT(exi != NULL);
   1894 	ASSERT(exi->exi_export.ex_flags & EX_LOG);
   1895 
   1896 	bzero(&req, sizeof (req));
   1897 	req.rq_prog = NFSLOG_PROGRAM;
   1898 	req.rq_vers = NFSLOG_VERSION;
   1899 	req.rq_proc = NFSLOG_GETFH;
   1900 	req.rq_cred.oa_flavor = AUTH_NONE;
   1901 
   1902 	namebuf = kmem_alloc(MAXPATHLEN + 4, KM_SLEEP);
   1903 	if (seg == UIO_USERSPACE) {
   1904 		error = copyinstr(fname, namebuf, MAXPATHLEN, &len);
   1905 	} else {
   1906 		error = copystr(fname, namebuf, MAXPATHLEN, &len);
   1907 	}
   1908 
   1909 	if (!error) {
   1910 		gfh.gfh_fh_buf = *fh;
   1911 		gfh.gfh_path = namebuf;
   1912 
   1913 		nfslog_write_record(exi, &req, (caddr_t)&gfh, (caddr_t)&res,
   1914 		    cr, &nb, 0, NFSLOG_ONE_BUFFER);
   1915 	}
   1916 	kmem_free(namebuf, MAXPATHLEN + 4);
   1917 }
   1918