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