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