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 }