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