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 (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/cred.h>
  26 #include <sys/cmn_err.h>
  27 #include <sys/debug.h>
  28 #include <sys/systm.h>
  29 #include <sys/kmem.h>
  30 #include <sys/disp.h>
  31 #include <sys/atomic.h>
  32 #include <rpc/types.h>
  33 #include <nfs/nfs.h>
  34 #include <nfs/nfssys.h>
  35 #include <nfs/export.h>
  36 #include <nfs/rnode.h>
  37 #include <rpc/auth.h>
  38 #include <rpc/svc.h>
  39 #include <rpc/xdr.h>
  40 #include <rpc/clnt.h>
  41 #include <nfs/nfs_log.h>
  42 
  43 #define NUM_RECORDS_TO_WRITE 256
  44 #define NUM_BYTES_TO_WRITE 65536
  45 
  46 extern krwlock_t exported_lock;
  47 
  48 static int nfslog_num_records_to_write = NUM_RECORDS_TO_WRITE;
  49 static int nfslog_num_bytes_to_write = NUM_BYTES_TO_WRITE;
  50 
  51 /*
  52  * This struct is used to 'hide' the details of managing the log
  53  * records internally to the logging code.  Allocation routines
  54  * are used to obtain pieces of memory for XDR encoding.  This struct
  55  * is a 'header' to those areas and a opaque cookie is used to pass
  56  * this data structure between the allocating function and the put
  57  * function.
  58  */
  59 struct lr_alloc {
  60         struct lr_alloc         *next;          /* links for write queuing */
  61         struct lr_alloc         *prev;
  62 #define LR_ALLOC_NOFREE 0x1                     /* not present, call free */
  63         int                     lr_flags;
  64         caddr_t                 log_record;     /* address to XDR encoding */
  65         size_t                  size;           /* final size of encoding */
  66         struct kmem_cache       *alloc_cache;   /* keep track of cache ptr */
  67         struct exportinfo       *exi;           /* who are we related to? */
 
 578         kmem_free(lfp, sizeof (*lfp));
 579         rfsl_log_file--;
 580 }
 581 
 582 /*
 583  * Allocates a record of the size specified.
 584  * 'exi' identifies the exportinfo structure being logged.
 585  * 'size' indicates how much memory should be allocated
 586  * 'cookie' is used to store an opaque value for the caller for later use
 587  * 'flags' currently ignored.
 588  *
 589  * Returns a pointer to the beginning of the allocated memory.
 590  * 'cookie' is a pointer to the 'lr_alloc' struct; this will be used
 591  * to keep track of the encoded record and contains all the info
 592  * for enqueuing the record on the log buffer for later writing.
 593  *
 594  * nfslog_record_put() must be used to 'free' this record or allocation.
 595  */
 596 /* ARGSUSED */
 597 void *
 598 nfslog_record_alloc(
 599         struct exportinfo *exi,
 600         int alloc_indx,
 601         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;
 
 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,
 772         struct lr_alloc *lrp_writers, 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) {
 
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) thread_create(NULL, 0, nfslog_do_flush,
1165                     tparams, 0, &p0, TS_RUN, 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;
 
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                 thread_exit();
1253                 /* NOTREACHED */
1254         }
1255 
1256         tparams->tp_error = error;
1257 }
1258 
1259 /*
1260  * Generate buffer_header.
1261  * 'loghdr' points the the buffer_header, and *reclen
1262  * contains the length of the buffer.
1263  */
1264 static void
1265 create_buffer_header(caddr_t *loghdr, size_t *reclen, size_t *freesize)
1266 {
1267         timestruc_t             now;
1268         nfslog_buffer_header    lh;
1269         XDR                     xdrs;
1270         unsigned int            final_size;
1271 
1272 
1273         /* pick some size that will hold the buffer_header */
 
1512                 nfslog_vers_disptable},
1513 
1514         {NFSLOG_PROGRAM, NFSLOG_VERSMIN,
1515                 (sizeof (nfslog_nfslog_vers_disptable) /
1516                 sizeof (nfslog_nfslog_vers_disptable[0])),
1517                 nfslog_nfslog_vers_disptable},
1518 };
1519 
1520 static int      nfslog_dispatch_table_arglen = sizeof (nfslog_dispatch_table) /
1521                                         sizeof (nfslog_dispatch_table[0]);
1522 
1523 /*
1524  * This function will determine the appropriate export info struct to use
1525  * and allocate a record id to be used in the written log buffer.
1526  * Usually this is a straightforward operation but the existence of the
1527  * multicomponent lookup and its semantics of crossing file system
1528  * boundaries add to the complexity.  See the comments below...
1529  */
1530 struct exportinfo *
1531 nfslog_get_exi(
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 != 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));
 
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         extern struct exportinfo *exi_public;
1768         char *pubpath;
1769 
1770         rw_enter(&exported_lock, RW_READER);
1771 
1772         *alloc_length = exi_public->exi_export.ex_pathlen + 1;
1773         pubpath = kmem_alloc(*alloc_length, KM_SLEEP);
1774 
1775         (void) strcpy(pubpath, exi_public->exi_export.ex_path);
1776 
1777         rw_exit(&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));
 
1853 nfslog_unshare_record(struct exportinfo *exi, cred_t *cr)
1854 {
1855         struct svc_req  req;
1856         int             res = 0;
1857         struct netbuf   nb = {0, 0, NULL};
1858 
1859         ASSERT(exi != NULL);
1860         ASSERT(exi->exi_export.ex_flags & EX_LOG);
1861 
1862         bzero(&req, sizeof (req));
1863         req.rq_prog = NFSLOG_PROGRAM;
1864         req.rq_vers = NFSLOG_VERSION;
1865         req.rq_proc = NFSLOG_UNSHARE;
1866         req.rq_cred.oa_flavor = AUTH_NONE;
1867         nfslog_write_record(exi, &req,
1868             (caddr_t)exi, (caddr_t)&res, cr, &nb, 0, NFSLOG_ONE_BUFFER);
1869 }
1870 
1871 
1872 void
1873 nfslog_getfh(struct exportinfo *exi,
1874         fhandle *fh,
1875         char *fname,
1876         enum uio_seg seg,
1877         cred_t *cr)
1878 {
1879         struct svc_req  req;
1880         int             res = 0;
1881         struct netbuf   nb = {0, 0, NULL};
1882         int             error = 0;
1883         char            *namebuf;
1884         size_t          len;
1885         nfslog_getfhargs gfh;
1886 
1887         ASSERT(exi != NULL);
1888         ASSERT(exi->exi_export.ex_flags & EX_LOG);
1889 
1890         bzero(&req, sizeof (req));
1891         req.rq_prog = NFSLOG_PROGRAM;
1892         req.rq_vers = NFSLOG_VERSION;
1893         req.rq_proc = NFSLOG_GETFH;
1894         req.rq_cred.oa_flavor = AUTH_NONE;
1895 
1896         namebuf = kmem_alloc(MAXPATHLEN + 4, KM_SLEEP);
 | 
   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? */
 
 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;
 
 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) {
 
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;
 
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 */
 
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));
 
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));
 
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);
 |