xref: /titanic_41/usr/src/uts/common/fs/cachefs/cachefs_log.c (revision 9e86db79b7d1bbc5f2f04e99954cbd5eae0e22bb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/errno.h>
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/user.h>
33 #include <sys/stat.h>
34 #include <sys/kstat.h>
35 #include <sys/time.h>
36 #include <sys/vfs.h>
37 #include <sys/vnode.h>
38 #include <sys/file.h>
39 #include <rpc/types.h>
40 #include <rpc/xdr.h>
41 #include <sys/mode.h>
42 #include <sys/pathname.h>
43 #include <sys/cmn_err.h>
44 #include <sys/debug.h>
45 #include <sys/fs/cachefs_fs.h>
46 #include <sys/fs/cachefs_log.h>
47 #include <vm/seg.h>
48 #include <vm/seg_map.h>
49 #include <sys/sysmacros.h>
50 
51 /*
52  * ino64_t is a unsigned long on LP64 and unsigned long long on ILP32,
53  * the compiler emits many warnings when calling xdr_u_longlong_t with an
54  * unsigned long pointer on LP64 even though it's safe.
55  */
56 #define	xdr_ino64(xdrs, p)	xdr_u_longlong_t((xdrs), (u_longlong_t *)(p))
57 
58 /*
59  * cfs_time_t is an int in both LP64 and ILP32. To avoid compiler warnings
60  * define its xdr here explicitly
61  */
62 #define	xdr_cfs_time_t(xdrs, p)	xdr_int((xdrs), (int *)(p))
63 
64 #define	CACHEFS_LOG_MAX_BUFFERED	65536
65 #define	CACHEFS_LOG_LOWATER		 8192
66 #define	CACHEFS_LOG_ENCODE_SIZE		 4096
67 
68 #if (defined(_SYSCALL32_IMPL) || defined(_LP64))
69 
70 #define	OUT_IF_TIME_OVERFLOW(cachep, time)				\
71 	if (TIME_OVERFLOW(time)) {					\
72 		cachefs_log_error(cachep, EOVERFLOW, 1);		\
73 		goto out;						\
74 	}
75 
76 #define	RET_IF_TIME_OVERFLOW(cachep, time)				\
77 	if (TIME_OVERFLOW(time)) {					\
78 		cachefs_log_error(cachep, EOVERFLOW, 1);		\
79 		return;							\
80 	}
81 
82 #else /* not (_SYSCALL32_IMPL || _LP64) */
83 
84 #define	OUT_IF_TIME_OVERFLOW(cachep, time)
85 
86 #define	RET_IF_TIME_OVERFLOW(cachep, time)
87 
88 #endif /* (_SYSCALL32_IMPL || _LP64) */
89 
90 typedef struct cachefs_log_work_list {
91 	void *data;
92 	size_t size;
93 	xdrproc_t translate;
94 	struct cachefs_log_work_list *next;
95 } *cachefs_log_work_list_t;
96 
97 /* forward declarations of static functions */
98 static void cachefs_log_enqueue(cachefscache_t *, void *, int, xdrproc_t);
99 static int cachefs_log_save_lc(cachefscache_t *);
100 static int cachefs_log_write_header(struct vnode *, cachefscache_t *, int);
101 
102 static bool_t cachefs_xdr_logfile_header(XDR *,
103     struct cachefs_log_logfile_header *);
104 static bool_t cachefs_xdr_mount(XDR *, struct cachefs_log_mount_record *);
105 static bool_t cachefs_xdr_umount(XDR *, struct cachefs_log_umount_record *);
106 static bool_t cachefs_xdr_getpage(XDR *, struct cachefs_log_getpage_record *);
107 static bool_t cachefs_xdr_readdir(XDR *, struct cachefs_log_readdir_record *);
108 static bool_t cachefs_xdr_readlink(XDR *,
109     struct cachefs_log_readlink_record *);
110 static bool_t cachefs_xdr_remove(XDR *, struct cachefs_log_remove_record *);
111 static bool_t cachefs_xdr_rmdir(XDR *, struct cachefs_log_rmdir_record *);
112 static bool_t cachefs_xdr_truncate(XDR *,
113     struct cachefs_log_truncate_record *);
114 static bool_t cachefs_xdr_putpage(XDR *, struct cachefs_log_putpage_record *);
115 static bool_t cachefs_xdr_create(XDR *, struct cachefs_log_create_record *);
116 static bool_t cachefs_xdr_mkdir(XDR *, struct cachefs_log_mkdir_record *);
117 static bool_t cachefs_xdr_rename(XDR *, struct cachefs_log_rename_record *);
118 static bool_t cachefs_xdr_symlink(XDR *, struct cachefs_log_symlink_record *);
119 static bool_t cachefs_xdr_populate(XDR *,
120     struct cachefs_log_populate_record *);
121 static bool_t cachefs_xdr_csymlink(XDR *,
122     struct cachefs_log_csymlink_record *);
123 static bool_t cachefs_xdr_filldir(XDR *,
124     struct cachefs_log_filldir_record *);
125 static bool_t cachefs_xdr_mdcreate(XDR *,
126     struct cachefs_log_mdcreate_record *);
127 static bool_t cachefs_xdr_gpfront(XDR *,
128     struct cachefs_log_gpfront_record *);
129 static bool_t cachefs_xdr_rfdir(XDR *,
130     struct cachefs_log_rfdir_record *);
131 static bool_t cachefs_xdr_ualloc(XDR *,
132     struct cachefs_log_ualloc_record *);
133 static bool_t cachefs_xdr_calloc(XDR *,
134     struct cachefs_log_calloc_record *);
135 static bool_t cachefs_xdr_nocache(XDR *,
136     struct cachefs_log_nocache_record *);
137 
138 
139 extern time_t time;
140 
141 /*
142  * cachefs_log_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
143  *
144  * called from /dev/kstat or somesuch.
145  *
146  */
147 
148 int
149 cachefs_log_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
150 {
151 	cachefs_log_control_t *lc = (cachefs_log_control_t *)ksp->ks_data;
152 	cachefs_log_control_t *buflc = (cachefs_log_control_t *)buf;
153 	cachefscache_t *cachep = (cachefscache_t *)(uintptr_t)lc->lc_cachep;
154 	cachefs_log_cookie_t *cl = cachep->c_log;
155 	int error = 0;
156 
157 	ASSERT(MUTEX_HELD(&cachep->c_log_mutex));
158 
159 	/* if they just want to read the kstat, get that out of the way. */
160 	if (rw != KSTAT_WRITE) {
161 		bcopy(lc, buflc, sizeof (*lc));
162 		return (0);
163 	}
164 
165 	/* make sure they're passing us a valid control cookie */
166 	if ((buflc->lc_cachep != lc->lc_cachep) ||
167 	    (buflc->lc_magic != CACHEFS_LOG_MAGIC))
168 		return (EIO);
169 
170 	/*
171 	 * if logging is currently off
172 	 *   o insist that we're being handed a logfile path
173 	 *   o set cl, and give our cachep its value
174 	 *
175 	 * after that, if something goes wrong, we must call
176 	 * cachefs_log_error to clear cachep->c_log.
177 	 */
178 	if (cl == NULL) {
179 		if (buflc->lc_path[0] == '\0')
180 			return (EIO);
181 		cl = cachep->c_log = cachefs_log_create_cookie(lc);
182 		if (cl == NULL) {
183 			cachefs_log_error(cachep, ENOMEM, 0);
184 			return (EIO);
185 		}
186 	}
187 
188 	/*
189 	 * if we're being handed an empty logpath, then they must be
190 	 * turning off logging; also, logging must have been turned on
191 	 * before, or else the previous paragraph would have caught
192 	 * it.
193 	 */
194 	if (buflc->lc_path[0] == '\0') {
195 		cachefs_log_process_queue(cachep, 0);
196 		cachep->c_log = NULL;
197 		cachefs_log_destroy_cookie(cl);
198 		bzero(lc, sizeof (*lc));
199 		lc->lc_magic = CACHEFS_LOG_MAGIC;
200 		lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
201 		(void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred, NULL,
202 		    0);
203 		return (0);
204 	}
205 
206 	/*
207 	 * if we get here, we know that we're being handed a valid log
208 	 * control cookie, and that a path is set.  try to open the
209 	 * log file, even if it's the same path, because they might
210 	 * have removed the old log file out from under us.  if it
211 	 * really is the same file, no harm done.
212 	 */
213 	if ((error = cachefs_log_logfile_open(cachep, buflc->lc_path)) != 0) {
214 		cachefs_log_error(cachep, error, 0);
215 		return (EIO);
216 	}
217 
218 	/*
219 	 * if we get here, we have a valid logfile open.  we don't do
220 	 * anything here with the bitmap of what's being logged, other
221 	 * than copy it.  we're home free!
222 	 */
223 	bcopy(buflc, lc, sizeof (*lc));
224 	if ((error = cachefs_log_save_lc(cachep)) != 0) {
225 		cachefs_log_error(cachep, error, 0);
226 		return (EIO);
227 	}
228 
229 	return (0);
230 }
231 
232 static int
233 cachefs_log_save_lc(cachefscache_t *cachep)
234 {
235 	cachefs_log_control_t *lc = (cachefs_log_control_t *)cachep->c_log_ctl;
236 	struct vnode *savevp;
237 	struct vattr attr;
238 	int error = 0;
239 
240 	if (lc == NULL)
241 		return (EINVAL);
242 
243 	attr.va_mode = S_IFREG | 0666;
244 	attr.va_uid = 0;
245 	attr.va_gid = 0;
246 	attr.va_type = VREG;
247 	attr.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
248 
249 	if (((error = VOP_LOOKUP(cachep->c_dirvp, LOG_STATUS_NAME, &savevp,
250 	    NULL, 0, NULL, kcred, NULL, NULL, NULL)) != 0) &&
251 	    ((error = VOP_CREATE(cachep->c_dirvp, LOG_STATUS_NAME, &attr, EXCL,
252 	    0600, &savevp, kcred, 0, NULL, NULL)) != 0))
253 		return (error);
254 	ASSERT(savevp != NULL);
255 	if (savevp == NULL)
256 		return (ENOENT);
257 
258 	error = vn_rdwr(UIO_WRITE, savevp,
259 	    (caddr_t)lc, sizeof (*lc),
260 	    0LL, UIO_SYSSPACE, FSYNC, (rlim64_t)RLIM_INFINITY, kcred, NULL);
261 
262 	VN_RELE(savevp);
263 
264 	return (error);
265 }
266 
267 /*
268  * cachefs_log_cookie_t *cachefs_log_create_cookie(void *)
269  *
270  * creates and initializes the cookie, which lives in cachep.  called
271  * from either a kstat write which turns on logging, or from
272  * initializing cachep when a log-info-file exists.
273  */
274 
275 cachefs_log_cookie_t *
276 cachefs_log_create_cookie(cachefs_log_control_t *lc)
277 {
278 	cachefs_log_cookie_t *rc;
279 
280 	rc = cachefs_kmem_zalloc(sizeof (*rc), KM_NOSLEEP);
281 	if (rc == NULL)
282 		return (NULL);
283 
284 	rc->cl_magic = CACHEFS_LOG_MAGIC;
285 	rc->cl_logctl = lc;
286 
287 	return (rc);
288 }
289 
290 /*
291  * void cachefs_log_destroy_cookie(cachefs_log_cookie_t *)
292  *
293  * destroys the log cookie.  called from cachefs_log_error, or from
294  * destroying the cachep.
295  *
296  */
297 
298 void
299 cachefs_log_destroy_cookie(cachefs_log_cookie_t *cl)
300 {
301 	cachefs_log_work_list_t node, oldnode;
302 
303 	if (cl == NULL)
304 		return;
305 
306 	ASSERT(cl->cl_magic == CACHEFS_LOG_MAGIC);
307 
308 	cl->cl_magic++;
309 	node = cl->cl_head;
310 	while (node != NULL) {
311 		cachefs_kmem_free(node->data, node->size);
312 		oldnode = node;
313 		node = node->next;
314 		cachefs_kmem_free(oldnode, sizeof (*oldnode));
315 	}
316 	if (cl->cl_logvp != NULL)
317 		VN_RELE(cl->cl_logvp);
318 	cachefs_kmem_free(cl, sizeof (*cl));
319 }
320 
321 /*
322  * int cachefs_log_logfile_open(cachefscache_t *, char *)
323  *
324  * opens the logfile, and stores the path string if its successful.
325  *
326  * returns an errno if one occurred.
327  *
328  */
329 
330 int
331 cachefs_log_logfile_open(cachefscache_t *cachep, char *path)
332 {
333 	cachefs_log_cookie_t *cl = cachep->c_log;
334 	struct vnode *newvp = NULL;
335 	int error = 0;
336 	int i;
337 
338 	ASSERT(MUTEX_HELD(&cachep->c_log_mutex));
339 	ASSERT(cl != NULL);
340 	ASSERT(cl->cl_magic == CACHEFS_LOG_MAGIC);
341 
342 	/* lookup the pathname -- it must already exist! */
343 	error = lookupname(path, UIO_SYSSPACE, FOLLOW, NULL, &newvp);
344 	if (error)
345 		goto out;
346 	ASSERT(newvp != NULL);
347 	if (newvp == NULL) {
348 		error = ENOENT; /* XXX this shouldn't happen (yeah right) */
349 		goto out;
350 	}
351 
352 	/* easy out if we just re-opened the same logfile */
353 	if (cl->cl_logvp == newvp) {
354 		VN_RELE(newvp);
355 		goto out;
356 	}
357 
358 	/* XXX we may change this to allow named pipes */
359 	if (newvp->v_type != VREG) {
360 		error = EINVAL;
361 		goto out;
362 	}
363 	if (vn_matchops(newvp, cachefs_getvnodeops())) {
364 		error = EINVAL;
365 		goto out;
366 	}
367 
368 	/* write out the header */
369 	error = cachefs_log_write_header(newvp, cachep, 0);
370 	if (error)
371 		goto out;
372 
373 	/* if we get here, we successfully opened the log. */
374 	if (cl->cl_logvp != NULL)
375 		VN_RELE(cl->cl_logvp);
376 	cl->cl_logvp = newvp;
377 
378 	/*
379 	 * `fake' a mount entry for each mounted cachefs filesystem.
380 	 * this is overkill, but it's easiest and most foolproof way
381 	 * to do things here.  the user-level consumers of the logfile
382 	 * have to expect extraneous mount entries and deal with it
383 	 * correctly.
384 	 */
385 	mutex_exit(&cachep->c_log_mutex);
386 	for (i = 0; i < cachefs_kstat_key_n; i++) {
387 		cachefs_kstat_key_t *k;
388 		struct vfs *vfsp;
389 		struct fscache *fscp;
390 
391 		k = cachefs_kstat_key + i;
392 		if (! k->ks_mounted)
393 			continue;
394 
395 		vfsp = (struct vfs *)(uintptr_t)k->ks_vfsp;
396 		fscp = VFS_TO_FSCACHE(vfsp);
397 		cachefs_log_mount(cachep, 0, vfsp, fscp,
398 		    (char *)(uintptr_t)k->ks_mountpoint, UIO_SYSSPACE,
399 		    (char *)(uintptr_t)k->ks_cacheid);
400 	}
401 	mutex_enter(&cachep->c_log_mutex);
402 
403 out:
404 	if ((error != 0) && (newvp != NULL))
405 		VN_RELE(newvp);
406 	return (error);
407 }
408 
409 /*
410  * called when an error occurred during logging.  send the error to
411  * syslog, invalidate the logfile, and stop logging.
412  */
413 
414 void
415 cachefs_log_error(cachefscache_t *cachep, int error, int getlock)
416 {
417 	cachefs_log_cookie_t *cl = cachep->c_log;
418 	cachefs_log_control_t *lc = cachep->c_log_ctl;
419 	int writable = 0;
420 
421 	ASSERT((getlock) || (MUTEX_HELD(&cachep->c_log_mutex)));
422 
423 	if (getlock)
424 		mutex_enter(&cachep->c_log_mutex);
425 
426 	if ((cachep->c_flags & (CACHE_NOCACHE | CACHE_NOFILL)) == 0)
427 		writable = 1;
428 
429 	cmn_err(CE_WARN, "cachefs logging: error %d\n", error);
430 
431 	if ((writable) && (cl != NULL) && (cl->cl_logvp != NULL))
432 		(void) cachefs_log_write_header(cl->cl_logvp, cachep, error);
433 
434 	cachep->c_log = NULL;
435 	if (cl != NULL)
436 		cachefs_log_destroy_cookie(cl);
437 	bzero(lc, sizeof (cachefs_log_control_t));
438 	lc->lc_magic = CACHEFS_LOG_MAGIC;
439 	lc->lc_cachep = (uint64_t)(uintptr_t)cachep;
440 	if (writable)
441 		(void) VOP_REMOVE(cachep->c_dirvp, LOG_STATUS_NAME, kcred, NULL,
442 		    0);
443 
444 	if (getlock)
445 		mutex_exit(&cachep->c_log_mutex);
446 }
447 
448 static int
449 cachefs_log_write_header(struct vnode *vp, cachefscache_t *cachep, int error)
450 {
451 	struct cachefs_log_logfile_header header, oheader;
452 	char buffy[2 * sizeof (header)];
453 	int Errno = 0;
454 	struct vattr attr;
455 	int gotold = 0;
456 	XDR xdrm;
457 
458 	attr.va_mask = AT_SIZE;
459 	if ((error = VOP_GETATTR(vp, &attr, 0, kcred, NULL)) != 0)
460 		goto out;
461 	if (attr.va_size != 0) {
462 		error = vn_rdwr(UIO_READ, vp, buffy,
463 		    MIN(sizeof (buffy), attr.va_size),
464 		    0LL, UIO_SYSSPACE, 0, (rlim64_t)RLIM_INFINITY, kcred, NULL);
465 		if (error != 0)
466 			goto out;
467 
468 		xdrm.x_ops = NULL;
469 		xdrmem_create(&xdrm, buffy, sizeof (buffy), XDR_DECODE);
470 		if ((xdrm.x_ops == NULL) ||
471 		    (! cachefs_xdr_logfile_header(&xdrm, &oheader))) {
472 			if (xdrm.x_ops != NULL)
473 				xdr_destroy(&xdrm);
474 			error = EINVAL;
475 			goto out;
476 		}
477 		xdr_destroy(&xdrm);
478 		gotold = 1;
479 
480 		if (oheader.lh_magic != CACHEFS_LOG_MAGIC) {
481 			error = EINVAL;
482 			goto out;
483 		}
484 	}
485 
486 	xdrm.x_ops = NULL;
487 
488 	xdrmem_create(&xdrm, buffy, sizeof (buffy), XDR_ENCODE);
489 
490 	if (gotold) {
491 		header = oheader;
492 	} else {
493 		header.lh_magic = CACHEFS_LOG_MAGIC;
494 		header.lh_revision = CACHEFS_LOG_FILE_REV;
495 		header.lh_blocks = cachep->c_usage.cu_blksused;
496 		header.lh_files = cachep->c_usage.cu_filesused;
497 		header.lh_maxbsize = MAXBSIZE;
498 		header.lh_pagesize = PAGESIZE;
499 	}
500 
501 	/* these are things that we stomp over for every header write */
502 	header.lh_errno = Errno;
503 
504 	if (! cachefs_xdr_logfile_header(&xdrm, &header)) {
505 		error = ENOMEM;
506 		goto out;
507 	}
508 
509 	error = vn_rdwr(UIO_WRITE, vp,
510 	    (caddr_t)buffy, xdr_getpos(&xdrm),
511 	    0LL, UIO_SYSSPACE, FSYNC, (rlim64_t)RLIM_INFINITY, kcred, NULL);
512 	if (error)
513 		goto out;
514 
515 out:
516 	if (xdrm.x_ops != NULL)
517 		xdr_destroy(&xdrm);
518 	return (error);
519 }
520 
521 /*
522  * enqueues a record to be written to the logfile.
523  */
524 
525 static void
526 cachefs_log_enqueue(cachefscache_t *cachep, void *record, int size,
527     xdrproc_t translate)
528 {
529 	cachefs_log_cookie_t *cl;
530 	cachefs_log_work_list_t newnode, oldnode;
531 
532 	mutex_enter(&cachep->c_log_mutex);
533 	cl = cachep->c_log;
534 
535 	if (cl == NULL) { /* someone turned off logging out from under us */
536 		mutex_exit(&cachep->c_log_mutex);
537 		cachefs_kmem_free(record, size);
538 		return;
539 	}
540 	ASSERT(cl->cl_magic == CACHEFS_LOG_MAGIC);
541 
542 	cl->cl_size += size;
543 	newnode = cachefs_kmem_zalloc(sizeof (*newnode), KM_NOSLEEP);
544 	if ((cl->cl_size > CACHEFS_LOG_MAX_BUFFERED) || (newnode == NULL)) {
545 		cachefs_log_error(cachep, ENOMEM, 0);
546 		if (newnode != NULL)
547 			cachefs_kmem_free(newnode, sizeof (*newnode));
548 		cachefs_kmem_free(record, size);
549 		mutex_exit(&cachep->c_log_mutex);
550 		return;
551 	}
552 
553 	newnode->data = record;
554 	newnode->size = size;
555 	newnode->translate = translate;
556 	newnode->next = NULL;
557 
558 	oldnode = (cachefs_log_work_list_t)cl->cl_tail;
559 	if (oldnode != NULL)
560 		oldnode->next = newnode;
561 	cl->cl_tail = newnode;
562 	if (cl->cl_head == NULL)
563 		cl->cl_head = newnode;
564 	mutex_exit(&cachep->c_log_mutex);
565 
566 	if (cl->cl_size >= CACHEFS_LOG_LOWATER) {
567 		mutex_enter(&cachep->c_workq.wq_queue_lock);
568 		cachep->c_workq.wq_logwork = 1;
569 		cv_signal(&cachep->c_workq.wq_req_cv);
570 		mutex_exit(&cachep->c_workq.wq_queue_lock);
571 	}
572 }
573 
574 /*
575  * processes the log queue.  run by an async worker thread, or via
576  * cachefs_cache_sync().
577  */
578 
579 void
580 cachefs_log_process_queue(cachefscache_t *cachep, int getlock)
581 {
582 	cachefs_log_cookie_t *cl;
583 	cachefs_log_work_list_t work, workhead, oldwork;
584 	struct vnode *logvp = NULL;
585 	struct uio uio;
586 	struct iovec iov;
587 	int error = 0;
588 	XDR xdrm;
589 	char *buffy = NULL;
590 
591 	/*
592 	 * NULL out the x_ops field of XDR.  this way, if x_ops !=
593 	 * NULL, we know that we did the xdr*_create() successfully.
594 	 * this is documented in the xdr_create man page.
595 	 */
596 
597 	xdrm.x_ops = NULL;
598 
599 	/* see if we're still logging */
600 	if (getlock)
601 		mutex_enter(&cachep->c_log_mutex);
602 	cl = cachep->c_log;
603 	if ((cl == NULL) || (cl->cl_magic != CACHEFS_LOG_MAGIC)) {
604 		if (getlock)
605 			mutex_exit(&cachep->c_log_mutex);
606 		return;
607 	}
608 
609 	/* get the work, and let go of the mutex asap. */
610 	workhead = cl->cl_head;
611 	cl->cl_head = cl->cl_tail = NULL;
612 	cl->cl_size = 0;
613 	logvp = cl->cl_logvp;
614 	ASSERT(logvp != NULL);
615 	if (logvp == NULL) {
616 		if (getlock)
617 			mutex_exit(&cachep->c_log_mutex);
618 		return;
619 	}
620 	VN_HOLD(logvp);
621 	if (getlock)
622 		mutex_exit(&cachep->c_log_mutex);
623 
624 	/* we don't use vn_rdwr() because there's no way to set FNONBLOCK */
625 
626 	uio.uio_iov = &iov;
627 	uio.uio_iovcnt = 1;
628 	uio.uio_loffset = 0; /* fake -- we do FAPPEND */
629 	uio.uio_segflg = (short)UIO_SYSSPACE;
630 	uio.uio_llimit = MAXOFFSET_T;
631 	uio.uio_fmode = FWRITE | FNONBLOCK;
632 	uio.uio_extflg = UIO_COPY_CACHED;
633 
634 	buffy = cachefs_kmem_alloc(CACHEFS_LOG_ENCODE_SIZE, KM_SLEEP);
635 	xdrmem_create(&xdrm, buffy, CACHEFS_LOG_ENCODE_SIZE, XDR_ENCODE);
636 
637 	(void) VOP_RWLOCK(logvp, V_WRITELOCK_TRUE, NULL);
638 	for (work = workhead; work != NULL; work = work->next) {
639 		if (! (work->translate)(&xdrm, work->data)) {
640 			VOP_RWUNLOCK(logvp, V_WRITELOCK_TRUE, NULL);
641 			error = ENOMEM;
642 			goto out;
643 		}
644 
645 		iov.iov_base = buffy;
646 		iov.iov_len = uio.uio_resid = xdr_getpos(&xdrm);
647 		(void) xdr_setpos(&xdrm, 0);
648 
649 		error = VOP_WRITE(logvp, &uio, FAPPEND, kcred, NULL);
650 
651 		/* XXX future -- check for EAGAIN */
652 
653 		if ((error) || (uio.uio_resid)) {
654 			if (uio.uio_resid != 0)
655 				error = EIO;
656 			VOP_RWUNLOCK(logvp, V_WRITELOCK_TRUE, NULL);
657 			goto out;
658 		}
659 	}
660 	VOP_RWUNLOCK(logvp, V_WRITELOCK_TRUE, NULL);
661 
662 out:
663 	if (xdrm.x_ops != NULL)
664 		xdr_destroy(&xdrm);
665 	if (buffy != NULL)
666 		cachefs_kmem_free(buffy, CACHEFS_LOG_ENCODE_SIZE);
667 
668 	/*
669 	 * if an error occurred, we need to free the buffers ourselves.
670 	 * cachefs_destory_cookie() can't do it.
671 	 */
672 
673 	work = workhead;
674 	while (work != NULL) {
675 		cachefs_kmem_free(work->data, work->size);
676 		oldwork = work;
677 		work = work->next;
678 		cachefs_kmem_free(oldwork, sizeof (*oldwork));
679 	}
680 	if (logvp != NULL)
681 		VN_RELE(logvp);
682 	if (error) {
683 		cachefs_log_error(cachep, error, 1);
684 		return;
685 	}
686 }
687 
688 static bool_t
689 cachefs_xdr_logfile_header(XDR *xdrs, struct cachefs_log_logfile_header *h)
690 {
691 	if ((! xdr_u_int(xdrs, &h->lh_magic)) ||
692 	    (! xdr_u_int(xdrs, &h->lh_revision)) ||
693 	    (! xdr_int(xdrs, &h->lh_errno)) ||
694 	    (! xdr_u_int(xdrs, &h->lh_blocks)) ||
695 	    (! xdr_u_int(xdrs, &h->lh_files)) ||
696 	    (! xdr_u_int(xdrs, &h->lh_maxbsize)) ||
697 	    (! xdr_u_int(xdrs, &h->lh_pagesize)))
698 		return (FALSE);
699 
700 	return (TRUE);
701 }
702 
703 /*
704  * the routines for logging each transaction follow...
705  */
706 
707 void
708 cachefs_log_mount(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
709     fscache_t *fscp, char *upath, enum uio_seg seg, char *cacheid)
710 {
711 	struct cachefs_log_mount_record *record;
712 	char *cacheidt;
713 	char *path = NULL;
714 	size_t len;
715 	int len1, len2;
716 	int size, error;
717 
718 	/* In Solaris 64 - if can't represent time don't bother */
719 	OUT_IF_TIME_OVERFLOW(cachep, time)
720 	if (seg == UIO_USERSPACE) {
721 		path = cachefs_kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
722 		if (path == NULL) {
723 			cachefs_log_error(cachep, ENOMEM, 1);
724 			goto out;
725 		}
726 		if ((error = copyinstr(upath, path, MAXPATHLEN, &len)) != 0) {
727 			cachefs_log_error(cachep, error, 1);
728 			goto out;
729 		}
730 	} else {
731 		path = upath;
732 	}
733 
734 	len1 = (path != NULL) ? strlen(path) : 0;
735 	len2 = (cacheid != NULL) ? strlen(cacheid) : 0;
736 	size = (int)sizeof (*record) + len1 + len2 -
737 	    (int)CLPAD(cachefs_log_mount_record, path);
738 	record = cachefs_kmem_zalloc(size, KM_NOSLEEP);
739 	if (record == NULL) {
740 		cachefs_log_error(cachep, ENOMEM, 1);
741 		goto out;
742 	}
743 
744 	record->type = CACHEFS_LOG_MOUNT;
745 	record->time = time;
746 
747 	record->error = Errno;
748 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
749 
750 	if (fscp) {
751 		record->flags = fscp->fs_info.fi_mntflags;
752 		record->popsize = fscp->fs_info.fi_popsize;
753 		record->fgsize = fscp->fs_info.fi_fgsize;
754 	}
755 
756 	record->pathlen = (ushort_t)len1;
757 	record->cacheidlen = (ushort_t)len2;
758 	if (path != NULL)
759 		(void) strcpy(record->path, path);
760 	cacheidt = record->path + len1 + 1;
761 	if (cacheid != NULL)
762 		(void) strcpy(cacheidt, cacheid);
763 
764 	cachefs_log_enqueue(cachep, record, size, cachefs_xdr_mount);
765 
766 out:
767 	if ((seg == UIO_USERSPACE) && (path != NULL))
768 		cachefs_kmem_free(path, MAXPATHLEN);
769 }
770 
771 static bool_t
772 cachefs_xdr_mount(XDR *xdrs, struct cachefs_log_mount_record *rec)
773 {
774 	char *path = rec->path;
775 	char *cacheid;
776 
777 	cacheid = path + strlen(path) + 1;
778 
779 	if ((! xdr_int(xdrs, &rec->type)) ||
780 	    (! xdr_int(xdrs, &rec->error)) ||
781 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
782 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
783 	    (! xdr_u_int(xdrs, &rec->flags)) ||
784 	    (! xdr_u_int(xdrs, &rec->popsize)) ||
785 	    (! xdr_u_int(xdrs, &rec->fgsize)) ||
786 	    (! xdr_u_short(xdrs, &rec->pathlen)) ||
787 	    (! xdr_u_short(xdrs, &rec->cacheidlen)) ||
788 	    (! xdr_wrapstring(xdrs, &path)) ||
789 	    (! xdr_wrapstring(xdrs, &cacheid)))
790 		return (FALSE);
791 
792 	return (TRUE);
793 }
794 
795 void
796 cachefs_log_umount(cachefscache_t *cachep, int Errno, struct vfs *vfsp)
797 {
798 	struct cachefs_log_umount_record *record;
799 
800 	/* In Solaris 64 - if can't represent time don't bother */
801 	RET_IF_TIME_OVERFLOW(cachep, time)
802 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
803 	if (record == NULL) {
804 		cachefs_log_error(cachep, ENOMEM, 1);
805 		return;
806 	}
807 
808 	record->type = CACHEFS_LOG_UMOUNT;
809 	record->time = time;
810 
811 	record->error = Errno;
812 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
813 
814 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
815 	    cachefs_xdr_umount);
816 }
817 
818 static bool_t
819 cachefs_xdr_umount(XDR *xdrs, struct cachefs_log_umount_record *rec)
820 {
821 	if ((! xdr_int(xdrs, &rec->type)) ||
822 	    (! xdr_int(xdrs, &rec->error)) ||
823 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
824 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))))
825 		return (FALSE);
826 
827 	return (TRUE);
828 }
829 
830 void
831 cachefs_log_getpage(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
832     fid_t *fidp, ino64_t fileno, uid_t uid, u_offset_t offset, size_t len)
833 {
834 	struct cachefs_log_getpage_record *record;
835 
836 	/* In Solaris 64 - if can't represent time don't bother */
837 	RET_IF_TIME_OVERFLOW(cachep, time)
838 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
839 	if (record == NULL) {
840 		cachefs_log_error(cachep, ENOMEM, 1);
841 		return;
842 	}
843 
844 	record->type = CACHEFS_LOG_GETPAGE;
845 	record->time = time;
846 
847 	record->error = Errno;
848 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
849 	if (fidp != NULL) {
850 		CACHEFS_FID_COPY(fidp, &record->fid);
851 	}
852 	record->fileno = fileno;
853 	record->uid = uid;
854 	record->offset = offset;
855 	record->len = (uint_t)len;
856 
857 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
858 	    cachefs_xdr_getpage);
859 }
860 
861 static bool_t
862 cachefs_xdr_getpage(XDR *xdrs, struct cachefs_log_getpage_record *rec)
863 {
864 	if ((! xdr_int(xdrs, &rec->type)) ||
865 	    (! xdr_int(xdrs, &rec->error)) ||
866 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
867 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
868 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
869 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
870 	    (! xdr_u_int(xdrs, &rec->uid)) ||
871 	    (! xdr_u_longlong_t(xdrs, &rec->offset)) ||
872 	    (! xdr_u_int(xdrs, &rec->len)))
873 		return (FALSE);
874 
875 	return (TRUE);
876 }
877 
878 void
879 cachefs_log_readdir(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
880     fid_t *fidp, ino64_t fileno, uid_t uid, u_offset_t offset, int eof)
881 {
882 	struct cachefs_log_readdir_record *record;
883 
884 	/* In Solaris 64 - if can't represent time don't bother */
885 	RET_IF_TIME_OVERFLOW(cachep, time)
886 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
887 	if (record == NULL) {
888 		cachefs_log_error(cachep, ENOMEM, 1);
889 		return;
890 	}
891 
892 	record->type = CACHEFS_LOG_READDIR;
893 	record->time = time;
894 
895 	record->error = Errno;
896 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
897 	if (fidp != NULL) {
898 		CACHEFS_FID_COPY(fidp, &record->fid);
899 	}
900 	record->fileno = fileno;
901 	record->uid = uid;
902 	record->offset = offset;
903 	record->eof = eof;
904 
905 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
906 	    cachefs_xdr_readdir);
907 }
908 
909 static bool_t
910 cachefs_xdr_readdir(XDR *xdrs, struct cachefs_log_readdir_record *rec)
911 {
912 	if ((! xdr_int(xdrs, &rec->type)) ||
913 	    (! xdr_int(xdrs, &rec->error)) ||
914 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
915 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
916 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
917 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
918 	    (! xdr_u_int(xdrs, &rec->uid)) ||
919 	    (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rec->offset)) ||
920 	    (! xdr_int(xdrs, &rec->eof)))
921 		return (FALSE);
922 
923 	return (TRUE);
924 }
925 
926 void
927 cachefs_log_readlink(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
928     fid_t *fidp, ino64_t fileno, uid_t uid, size_t length)
929 {
930 	struct cachefs_log_readlink_record *record;
931 
932 	/* In Solaris 64 - if can't represent time don't bother */
933 	RET_IF_TIME_OVERFLOW(cachep, time)
934 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
935 	if (record == NULL) {
936 		cachefs_log_error(cachep, ENOMEM, 1);
937 		return;
938 	}
939 
940 	record->type = CACHEFS_LOG_READLINK;
941 	record->time = time;
942 
943 	record->error = Errno;
944 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
945 	if (fidp != NULL) {
946 		CACHEFS_FID_COPY(fidp, &record->fid);
947 	}
948 	record->fileno = fileno;
949 	record->uid = uid;
950 	record->length = (uint_t)length;
951 
952 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
953 	    cachefs_xdr_readlink);
954 }
955 
956 static bool_t
957 cachefs_xdr_readlink(XDR *xdrs, struct cachefs_log_readlink_record *rec)
958 {
959 	if ((! xdr_int(xdrs, &rec->type)) ||
960 	    (! xdr_int(xdrs, &rec->error)) ||
961 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
962 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
963 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
964 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
965 	    (! xdr_u_int(xdrs, &rec->uid)) ||
966 	    (! xdr_u_int(xdrs, &rec->length)))
967 		return (FALSE);
968 
969 	return (TRUE);
970 }
971 
972 void
973 cachefs_log_remove(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
974     fid_t *fidp, ino64_t fileno, uid_t uid)
975 {
976 	struct cachefs_log_remove_record *record;
977 
978 	/* In Solaris 64 - if can't represent time don't bother */
979 	RET_IF_TIME_OVERFLOW(cachep, time)
980 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
981 	if (record == NULL) {
982 		cachefs_log_error(cachep, ENOMEM, 1);
983 		return;
984 	}
985 
986 	record->type = CACHEFS_LOG_REMOVE;
987 	record->time = time;
988 
989 	record->error = Errno;
990 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
991 	if (fidp != NULL) {
992 		CACHEFS_FID_COPY(fidp, &record->fid);
993 	}
994 	record->fileno = fileno;
995 	record->uid = uid;
996 
997 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
998 	    cachefs_xdr_remove);
999 }
1000 
1001 static bool_t
1002 cachefs_xdr_remove(XDR *xdrs, struct cachefs_log_remove_record *rec)
1003 {
1004 	if ((! xdr_int(xdrs, &rec->type)) ||
1005 	    (! xdr_int(xdrs, &rec->error)) ||
1006 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1007 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1008 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1009 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1010 	    (! xdr_u_int(xdrs, &rec->uid)))
1011 		return (FALSE);
1012 
1013 	return (TRUE);
1014 }
1015 
1016 void
1017 cachefs_log_rmdir(cachefscache_t *cachep, int Errno,
1018     struct vfs *vfsp, fid_t *fidp, ino64_t fileno, uid_t uid)
1019 {
1020 	struct cachefs_log_rmdir_record *record;
1021 
1022 	/* In Solaris 64 - if can't represent time don't bother */
1023 	RET_IF_TIME_OVERFLOW(cachep, time)
1024 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1025 	if (record == NULL) {
1026 		cachefs_log_error(cachep, ENOMEM, 1);
1027 		return;
1028 	}
1029 
1030 	record->type = CACHEFS_LOG_RMDIR;
1031 	record->time = time;
1032 
1033 	record->error = Errno;
1034 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1035 	if (fidp != NULL) {
1036 		CACHEFS_FID_COPY(fidp, &record->fid);
1037 	}
1038 	record->fileno = fileno;
1039 	record->uid = uid;
1040 
1041 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1042 	    cachefs_xdr_rmdir);
1043 }
1044 
1045 static bool_t
1046 cachefs_xdr_rmdir(XDR *xdrs, struct cachefs_log_rmdir_record *rec)
1047 {
1048 	if ((! xdr_int(xdrs, &rec->type)) ||
1049 	    (! xdr_int(xdrs, &rec->error)) ||
1050 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1051 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1052 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1053 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1054 	    (! xdr_u_int(xdrs, &rec->uid)))
1055 		return (FALSE);
1056 
1057 	return (TRUE);
1058 }
1059 
1060 void
1061 cachefs_log_truncate(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1062     fid_t *fidp, ino64_t fileno, uid_t uid, u_offset_t size)
1063 {
1064 	struct cachefs_log_truncate_record *record;
1065 
1066 	/* In Solaris 64 - if can't represent time don't bother */
1067 	RET_IF_TIME_OVERFLOW(cachep, time)
1068 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1069 	if (record == NULL) {
1070 		cachefs_log_error(cachep, ENOMEM, 1);
1071 		return;
1072 	}
1073 
1074 	record->type = CACHEFS_LOG_TRUNCATE;
1075 	record->time = time;
1076 
1077 	record->error = Errno;
1078 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1079 	if (fidp != NULL) {
1080 		CACHEFS_FID_COPY(fidp, &record->fid);
1081 	}
1082 	record->fileno = fileno;
1083 	record->uid = uid;
1084 	record->size = size;
1085 
1086 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1087 	    cachefs_xdr_truncate);
1088 }
1089 
1090 static bool_t
1091 cachefs_xdr_truncate(XDR *xdrs, struct cachefs_log_truncate_record *rec)
1092 {
1093 	if ((! xdr_int(xdrs, &rec->type)) ||
1094 	    (! xdr_int(xdrs, &rec->error)) ||
1095 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1096 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1097 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1098 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1099 	    (! xdr_u_int(xdrs, &rec->uid)) ||
1100 	    (! xdr_u_longlong_t(xdrs, &rec->size)))
1101 		return (FALSE);
1102 
1103 	return (TRUE);
1104 }
1105 
1106 void
1107 cachefs_log_putpage(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1108     fid_t *fidp, ino64_t fileno, uid_t uid, u_offset_t offset, size_t len)
1109 {
1110 	struct cachefs_log_putpage_record *record;
1111 
1112 	/* In Solaris 64 - if can't represent time don't bother */
1113 	RET_IF_TIME_OVERFLOW(cachep, time)
1114 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1115 	if (record == NULL) {
1116 		cachefs_log_error(cachep, ENOMEM, 1);
1117 		return;
1118 	}
1119 
1120 	record->type = CACHEFS_LOG_PUTPAGE;
1121 	record->time = time;
1122 
1123 	record->error = Errno;
1124 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1125 	if (fidp != NULL) {
1126 		CACHEFS_FID_COPY(fidp, &record->fid);
1127 	}
1128 	record->fileno = fileno;
1129 	record->uid = uid;
1130 	record->offset = offset;
1131 	record->len = (uint_t)len;
1132 
1133 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1134 	    cachefs_xdr_putpage);
1135 }
1136 
1137 static bool_t
1138 cachefs_xdr_putpage(XDR *xdrs, struct cachefs_log_putpage_record *rec)
1139 {
1140 	if ((! xdr_int(xdrs, &rec->type)) ||
1141 	    (! xdr_int(xdrs, &rec->error)) ||
1142 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1143 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1144 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1145 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1146 	    (! xdr_u_int(xdrs, &rec->uid)) ||
1147 	    (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rec->offset)) ||
1148 	    (! xdr_u_int(xdrs, &rec->len)))
1149 		return (FALSE);
1150 
1151 	return (TRUE);
1152 }
1153 
1154 void
1155 cachefs_log_create(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1156     fid_t *filefidp, ino64_t fileno, uid_t uid)
1157 {
1158 	struct cachefs_log_create_record *record;
1159 
1160 	/* In Solaris 64 - if can't represent time don't bother */
1161 	RET_IF_TIME_OVERFLOW(cachep, time)
1162 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1163 	if (record == NULL) {
1164 		cachefs_log_error(cachep, ENOMEM, 1);
1165 		return;
1166 	}
1167 
1168 	record->type = CACHEFS_LOG_CREATE;
1169 	record->time = time;
1170 
1171 	record->error = Errno;
1172 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1173 	if (filefidp != NULL) {
1174 		CACHEFS_FID_COPY(filefidp, &record->fid);
1175 	}
1176 	record->fileno = fileno;
1177 	record->uid = uid;
1178 
1179 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1180 	    cachefs_xdr_create);
1181 }
1182 
1183 static bool_t
1184 cachefs_xdr_create(XDR *xdrs, struct cachefs_log_create_record *rec)
1185 {
1186 	if ((! xdr_int(xdrs, &rec->type)) ||
1187 	    (! xdr_int(xdrs, &rec->error)) ||
1188 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1189 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1190 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1191 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1192 	    (! xdr_u_int(xdrs, &rec->uid)))
1193 		return (FALSE);
1194 
1195 	return (TRUE);
1196 }
1197 
1198 void
1199 cachefs_log_mkdir(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1200     fid_t *cfidp, ino64_t fileno, uid_t uid)
1201 {
1202 	struct cachefs_log_mkdir_record *record;
1203 	int size;
1204 
1205 	/* In Solaris 64 - if can't represent time don't bother */
1206 	RET_IF_TIME_OVERFLOW(cachep, time)
1207 	size = (int)sizeof (*record);
1208 	record = cachefs_kmem_zalloc(size, KM_NOSLEEP);
1209 	if (record == NULL) {
1210 		cachefs_log_error(cachep, ENOMEM, 1);
1211 		return;
1212 	}
1213 
1214 	record->type = CACHEFS_LOG_MKDIR;
1215 	record->time = time;
1216 
1217 	record->error = Errno;
1218 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1219 	if (cfidp != NULL) {
1220 		CACHEFS_FID_COPY(cfidp, &record->fid);
1221 	}
1222 	record->fileno = fileno;
1223 	record->uid = uid;
1224 
1225 	cachefs_log_enqueue(cachep, record, size,
1226 	    cachefs_xdr_mkdir);
1227 }
1228 
1229 static bool_t
1230 cachefs_xdr_mkdir(XDR *xdrs, struct cachefs_log_mkdir_record *rec)
1231 {
1232 	if ((! xdr_int(xdrs, &rec->type)) ||
1233 	    (! xdr_int(xdrs, &rec->error)) ||
1234 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1235 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1236 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1237 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1238 	    (! xdr_u_int(xdrs, &rec->uid)))
1239 		return (FALSE);
1240 
1241 	return (TRUE);
1242 }
1243 
1244 void
1245 cachefs_log_rename(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1246     fid_t *gfp, ino64_t fileno, int removed, uid_t uid)
1247 {
1248 	struct cachefs_log_rename_record *record;
1249 
1250 	/* In Solaris 64 - if can't represent time don't bother */
1251 	RET_IF_TIME_OVERFLOW(cachep, time)
1252 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1253 	if (record == NULL) {
1254 		cachefs_log_error(cachep, ENOMEM, 1);
1255 		return;
1256 	}
1257 
1258 	record->type = CACHEFS_LOG_RENAME;
1259 	record->time = time;
1260 
1261 	record->error = Errno;
1262 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1263 	if (gfp != NULL) {
1264 		CACHEFS_FID_COPY(gfp, &record->gone);
1265 	}
1266 	record->fileno = fileno;
1267 	record->removed = removed;
1268 	record->uid = uid;
1269 
1270 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1271 	    cachefs_xdr_rename);
1272 }
1273 
1274 static bool_t
1275 cachefs_xdr_rename(XDR *xdrs, struct cachefs_log_rename_record *rec)
1276 {
1277 	if ((! xdr_int(xdrs, &rec->type)) ||
1278 	    (! xdr_int(xdrs, &rec->error)) ||
1279 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1280 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1281 	    (! xdr_opaque(xdrs, (caddr_t)&rec->gone, sizeof (rec->gone))) ||
1282 	    (! xdr_int(xdrs, &rec->removed)) ||
1283 	    (! xdr_u_int(xdrs, &rec->uid)))
1284 		return (FALSE);
1285 
1286 	return (TRUE);
1287 }
1288 
1289 
1290 void
1291 cachefs_log_symlink(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1292     fid_t *fidp, ino64_t fileno, uid_t uid, int size)
1293 {
1294 	struct cachefs_log_symlink_record *record;
1295 
1296 	/* In Solaris 64 - if can't represent time don't bother */
1297 	RET_IF_TIME_OVERFLOW(cachep, time)
1298 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1299 	if (record == NULL) {
1300 		cachefs_log_error(cachep, ENOMEM, 1);
1301 		return;
1302 	}
1303 
1304 	record->type = CACHEFS_LOG_SYMLINK;
1305 	record->time = time;
1306 
1307 	record->error = Errno;
1308 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1309 	if (fidp != NULL) {
1310 		CACHEFS_FID_COPY(fidp, &record->fid);
1311 	}
1312 	record->fileno = fileno;
1313 	record->uid = uid;
1314 	record->size = size;
1315 
1316 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1317 	    cachefs_xdr_symlink);
1318 }
1319 
1320 static bool_t
1321 cachefs_xdr_symlink(XDR *xdrs, struct cachefs_log_symlink_record *rec)
1322 {
1323 	if ((! xdr_int(xdrs, &rec->type)) ||
1324 	    (! xdr_int(xdrs, &rec->error)) ||
1325 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1326 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1327 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1328 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1329 	    (! xdr_u_int(xdrs, &rec->uid)) ||
1330 	    (! xdr_u_int(xdrs, &rec->size)))
1331 		return (FALSE);
1332 
1333 	return (TRUE);
1334 }
1335 
1336 void
1337 cachefs_log_populate(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1338     fid_t *fidp, ino64_t fileno, u_offset_t off, size_t popsize)
1339 {
1340 	struct cachefs_log_populate_record *record;
1341 
1342 	/* In Solaris 64 - if can't represent time don't bother */
1343 	RET_IF_TIME_OVERFLOW(cachep, time)
1344 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1345 	if (record == NULL) {
1346 		cachefs_log_error(cachep, ENOMEM, 1);
1347 		return;
1348 	}
1349 
1350 	record->type = CACHEFS_LOG_POPULATE;
1351 	record->time = time;
1352 	record->error = Errno;
1353 
1354 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1355 	if (fidp != NULL) {
1356 		CACHEFS_FID_COPY(fidp, &record->fid);
1357 	}
1358 	record->fileno = fileno;
1359 	record->off = off;
1360 	record->size = (int)popsize;
1361 
1362 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1363 	    cachefs_xdr_populate);
1364 }
1365 
1366 static bool_t
1367 cachefs_xdr_populate(XDR *xdrs, struct cachefs_log_populate_record *rec)
1368 {
1369 	if ((! xdr_int(xdrs, &rec->type)) ||
1370 	    (! xdr_int(xdrs, &rec->error)) ||
1371 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1372 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1373 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1374 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1375 	    (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rec->off)) ||
1376 	    (! xdr_u_int(xdrs, &rec->size)))
1377 		return (FALSE);
1378 
1379 	return (TRUE);
1380 }
1381 
1382 void
1383 cachefs_log_csymlink(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1384     fid_t *fidp, ino64_t fileno, int size)
1385 {
1386 	struct cachefs_log_csymlink_record *record;
1387 
1388 	/* In Solaris 64 - if can't represent time don't bother */
1389 	RET_IF_TIME_OVERFLOW(cachep, time)
1390 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1391 	if (record == NULL) {
1392 		cachefs_log_error(cachep, ENOMEM, 1);
1393 		return;
1394 	}
1395 
1396 	record->type = CACHEFS_LOG_CSYMLINK;
1397 	record->time = time;
1398 	record->error = Errno;
1399 
1400 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1401 	if (fidp != NULL) {
1402 		CACHEFS_FID_COPY(fidp, &record->fid);
1403 	}
1404 	record->fileno = fileno;
1405 	record->size = size;
1406 
1407 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1408 	    cachefs_xdr_csymlink);
1409 }
1410 
1411 static bool_t
1412 cachefs_xdr_csymlink(XDR *xdrs, struct cachefs_log_csymlink_record *rec)
1413 {
1414 	if ((! xdr_int(xdrs, &rec->type)) ||
1415 	    (! xdr_int(xdrs, &rec->error)) ||
1416 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1417 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1418 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1419 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1420 	    (! xdr_int(xdrs, &rec->size)))
1421 		return (FALSE);
1422 
1423 	return (TRUE);
1424 }
1425 
1426 void
1427 cachefs_log_filldir(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1428     fid_t *fidp, ino64_t fileno, u_offset_t size)
1429 {
1430 	struct cachefs_log_filldir_record *record;
1431 
1432 	/* In Solaris 64 - if can't represent time don't bother */
1433 	RET_IF_TIME_OVERFLOW(cachep, time)
1434 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1435 	if (record == NULL) {
1436 		cachefs_log_error(cachep, ENOMEM, 1);
1437 		return;
1438 	}
1439 
1440 	record->type = CACHEFS_LOG_FILLDIR;
1441 	record->time = time;
1442 	record->error = Errno;
1443 
1444 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1445 	if (fidp != NULL) {
1446 		CACHEFS_FID_COPY(fidp, &record->fid);
1447 	}
1448 	record->fileno = fileno;
1449 	record->size = (uint_t)size;
1450 
1451 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1452 	    cachefs_xdr_filldir);
1453 }
1454 
1455 static bool_t
1456 cachefs_xdr_filldir(XDR *xdrs, struct cachefs_log_filldir_record *rec)
1457 {
1458 	if ((! xdr_int(xdrs, &rec->type)) ||
1459 	    (! xdr_int(xdrs, &rec->error)) ||
1460 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1461 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1462 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1463 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1464 	    (! xdr_u_int(xdrs, (uint_t *)&rec->size)))
1465 		return (FALSE);
1466 
1467 	return (TRUE);
1468 }
1469 
1470 void
1471 cachefs_log_mdcreate(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1472     fid_t *fidp, ino64_t fileno, uint_t count)
1473 {
1474 	struct cachefs_log_mdcreate_record *record;
1475 
1476 	/* In Solaris 64 - if can't represent time don't bother */
1477 	RET_IF_TIME_OVERFLOW(cachep, time)
1478 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1479 	if (record == NULL) {
1480 		cachefs_log_error(cachep, ENOMEM, 1);
1481 		return;
1482 	}
1483 
1484 	record->type = CACHEFS_LOG_MDCREATE;
1485 	record->time = time;
1486 	record->error = Errno;
1487 
1488 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1489 	if (fidp != NULL) {
1490 		CACHEFS_FID_COPY(fidp, &record->fid);
1491 	}
1492 	record->fileno = fileno;
1493 	record->count = count;
1494 
1495 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1496 	    cachefs_xdr_mdcreate);
1497 }
1498 
1499 static bool_t
1500 cachefs_xdr_mdcreate(XDR *xdrs, struct cachefs_log_mdcreate_record *rec)
1501 {
1502 	if ((! xdr_int(xdrs, &rec->type)) ||
1503 	    (! xdr_int(xdrs, &rec->error)) ||
1504 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1505 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1506 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1507 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1508 	    (! xdr_u_int(xdrs, &rec->count)))
1509 		return (FALSE);
1510 
1511 	return (TRUE);
1512 }
1513 
1514 void
1515 cachefs_log_gpfront(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1516     fid_t *fidp, ino64_t fileno, uid_t uid, u_offset_t offset, uint_t len)
1517 {
1518 	struct cachefs_log_gpfront_record *record;
1519 
1520 	/* In Solaris 64 - if can't represent time don't bother */
1521 	RET_IF_TIME_OVERFLOW(cachep, time)
1522 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1523 	if (record == NULL) {
1524 		cachefs_log_error(cachep, ENOMEM, 1);
1525 		return;
1526 	}
1527 
1528 	record->type = CACHEFS_LOG_GPFRONT;
1529 	record->time = time;
1530 	record->error = Errno;
1531 
1532 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1533 	if (fidp != NULL) {
1534 		CACHEFS_FID_COPY(fidp, &record->fid);
1535 	}
1536 	record->fileno = fileno;
1537 	record->uid = uid;
1538 	record->off = offset;
1539 	record->len = len;
1540 
1541 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1542 	    cachefs_xdr_gpfront);
1543 }
1544 
1545 static bool_t
1546 cachefs_xdr_gpfront(XDR *xdrs, struct cachefs_log_gpfront_record *rec)
1547 {
1548 	if ((! xdr_int(xdrs, &rec->type)) ||
1549 	    (! xdr_int(xdrs, &rec->error)) ||
1550 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1551 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1552 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1553 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1554 	    (! xdr_u_int(xdrs, &rec->uid)) ||
1555 	    (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rec->off)) ||
1556 	    (! xdr_u_int(xdrs, &rec->len)))
1557 		return (FALSE);
1558 
1559 	return (TRUE);
1560 }
1561 
1562 void
1563 cachefs_log_rfdir(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1564     fid_t *fidp, ino64_t fileno, uid_t uid)
1565 {
1566 	struct cachefs_log_rfdir_record *record;
1567 
1568 	/* In Solaris 64 - if can't represent time don't bother */
1569 	RET_IF_TIME_OVERFLOW(cachep, time)
1570 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1571 	if (record == NULL) {
1572 		cachefs_log_error(cachep, ENOMEM, 1);
1573 		return;
1574 	}
1575 
1576 	record->type = CACHEFS_LOG_RFDIR;
1577 	record->time = time;
1578 	record->error = Errno;
1579 
1580 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1581 	if (fidp != NULL) {
1582 		CACHEFS_FID_COPY(fidp, &record->fid);
1583 	}
1584 	record->fileno = fileno;
1585 	record->uid = uid;
1586 
1587 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1588 	    cachefs_xdr_rfdir);
1589 }
1590 
1591 static bool_t
1592 cachefs_xdr_rfdir(XDR *xdrs, struct cachefs_log_rfdir_record *rec)
1593 {
1594 	if ((! xdr_int(xdrs, &rec->type)) ||
1595 	    (! xdr_int(xdrs, &rec->error)) ||
1596 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1597 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1598 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1599 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1600 	    (! xdr_u_int(xdrs, &rec->uid)))
1601 		return (FALSE);
1602 
1603 	return (TRUE);
1604 }
1605 
1606 void
1607 cachefs_log_ualloc(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1608     fid_t *fidp, ino64_t fileno, u_offset_t off, size_t len)
1609 {
1610 	struct cachefs_log_ualloc_record *record;
1611 
1612 	/* In Solaris 64 - if can't represent time don't bother */
1613 	RET_IF_TIME_OVERFLOW(cachep, time)
1614 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1615 	if (record == NULL) {
1616 		cachefs_log_error(cachep, ENOMEM, 1);
1617 		return;
1618 	}
1619 
1620 	record->type = CACHEFS_LOG_UALLOC;
1621 	record->time = time;
1622 	record->error = Errno;
1623 
1624 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1625 	if (fidp != NULL) {
1626 		CACHEFS_FID_COPY(fidp, &record->fid);
1627 	}
1628 	record->fileno = fileno;
1629 	record->off = off;
1630 	record->len = (uint_t)len;
1631 
1632 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1633 	    cachefs_xdr_ualloc);
1634 }
1635 
1636 static bool_t
1637 cachefs_xdr_ualloc(XDR *xdrs, struct cachefs_log_ualloc_record *rec)
1638 {
1639 	if ((! xdr_int(xdrs, &rec->type)) ||
1640 	    (! xdr_int(xdrs, &rec->error)) ||
1641 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1642 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1643 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1644 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1645 	    (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rec->off)) ||
1646 	    (! xdr_u_int(xdrs, (uint_t *)&rec->len)))
1647 		return (FALSE);
1648 
1649 	return (TRUE);
1650 }
1651 
1652 void
1653 cachefs_log_calloc(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1654     fid_t *fidp, ino64_t fileno, u_offset_t off, size_t len)
1655 {
1656 	struct cachefs_log_calloc_record *record;
1657 
1658 	/* In Solaris 64 - if can't represent time don't bother */
1659 	RET_IF_TIME_OVERFLOW(cachep, time)
1660 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1661 	if (record == NULL) {
1662 		cachefs_log_error(cachep, ENOMEM, 1);
1663 		return;
1664 	}
1665 
1666 	record->type = CACHEFS_LOG_CALLOC;
1667 	record->time = time;
1668 	record->error = Errno;
1669 
1670 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1671 	if (fidp != NULL) {
1672 		CACHEFS_FID_COPY(fidp, &record->fid);
1673 	}
1674 	record->fileno = fileno;
1675 	record->off = off;
1676 	record->len = (uint_t)len;
1677 
1678 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1679 	    cachefs_xdr_calloc);
1680 }
1681 
1682 static bool_t
1683 cachefs_xdr_calloc(XDR *xdrs, struct cachefs_log_calloc_record *rec)
1684 {
1685 	if ((! xdr_int(xdrs, &rec->type)) ||
1686 	    (! xdr_int(xdrs, &rec->error)) ||
1687 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1688 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1689 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1690 	    (! xdr_ino64(xdrs, &rec->fileno)) ||
1691 	    (! xdr_u_longlong_t(xdrs, (u_longlong_t *)&rec->off)) ||
1692 	    (! xdr_u_int(xdrs, &rec->len)))
1693 		return (FALSE);
1694 
1695 	return (TRUE);
1696 }
1697 
1698 void
1699 cachefs_log_nocache(cachefscache_t *cachep, int Errno, struct vfs *vfsp,
1700     fid_t *fidp, ino64_t fileno)
1701 {
1702 	struct cachefs_log_nocache_record *record;
1703 
1704 	/* In Solaris 64 - if can't represent time don't bother */
1705 	RET_IF_TIME_OVERFLOW(cachep, time)
1706 	record = cachefs_kmem_zalloc(sizeof (*record), KM_NOSLEEP);
1707 	if (record == NULL) {
1708 		cachefs_log_error(cachep, ENOMEM, 1);
1709 		return;
1710 	}
1711 
1712 	record->type = CACHEFS_LOG_NOCACHE;
1713 	record->time = time;
1714 	record->error = Errno;
1715 
1716 	record->vfsp = (uint64_t)(uintptr_t)vfsp;
1717 	if (fidp != NULL) {
1718 		CACHEFS_FID_COPY(fidp, &record->fid);
1719 	}
1720 	record->fileno = fileno;
1721 
1722 	cachefs_log_enqueue(cachep, record, (int)sizeof (*record),
1723 	    cachefs_xdr_nocache);
1724 
1725 }
1726 
1727 static bool_t
1728 cachefs_xdr_nocache(XDR *xdrs, struct cachefs_log_nocache_record *rec)
1729 {
1730 	if ((! xdr_int(xdrs, &rec->type)) ||
1731 	    (! xdr_int(xdrs, &rec->error)) ||
1732 	    (! xdr_cfs_time_t(xdrs, &rec->time)) ||
1733 	    (! xdr_opaque(xdrs, (caddr_t)&rec->vfsp, sizeof (rec->vfsp))) ||
1734 	    (! xdr_opaque(xdrs, (caddr_t)&rec->fid, sizeof (rec->fid))) ||
1735 	    (! xdr_ino64(xdrs, &rec->fileno)))
1736 		return (FALSE);
1737 
1738 	return (TRUE);
1739 }
1740