The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsserver/nfs_nfsdsocket.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: releng/12.0/sys/fs/nfsserver/nfs_nfsdsocket.c 340855 2018-11-23 21:08:11Z emaste $");
   38 
   39 /*
   40  * Socket operations for use by the nfs server.
   41  */
   42 
   43 #ifndef APPLEKEXT
   44 #include <fs/nfs/nfsport.h>
   45 
   46 extern struct nfsstatsv1 nfsstatsv1;
   47 extern struct nfsrvfh nfs_pubfh, nfs_rootfh;
   48 extern int nfs_pubfhset, nfs_rootfhset;
   49 extern struct nfsv4lock nfsv4rootfs_lock;
   50 extern struct nfsrv_stablefirst nfsrv_stablefirst;
   51 extern struct nfsclienthashhead *nfsclienthash;
   52 extern int nfsrv_clienthashsize;
   53 extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
   54 extern int nfsd_debuglevel;
   55 extern int nfsrv_layouthighwater;
   56 extern volatile int nfsrv_layoutcnt;
   57 NFSV4ROOTLOCKMUTEX;
   58 NFSSTATESPINLOCK;
   59 
   60 int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *,
   61     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
   62         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   63         nfsrvd_getattr,
   64         nfsrvd_setattr,
   65         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   66         nfsrvd_access,
   67         nfsrvd_readlink,
   68         nfsrvd_read,
   69         nfsrvd_write,
   70         nfsrvd_create,
   71         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   72         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   73         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   74         nfsrvd_remove,
   75         nfsrvd_remove,
   76         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   77         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
   78         nfsrvd_readdir,
   79         nfsrvd_readdirplus,
   80         nfsrvd_statfs,
   81         nfsrvd_fsinfo,
   82         nfsrvd_pathconf,
   83         nfsrvd_commit,
   84 };
   85 
   86 int (*nfsrv3_procs1[NFS_V3NPROCS])(struct nfsrv_descript *,
   87     int, vnode_t , vnode_t *, fhandle_t *,
   88     NFSPROC_T *, struct nfsexstuff *) = {
   89         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   90         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   91         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   92         nfsrvd_lookup,
   93         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   94         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   95         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   96         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   97         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
   98         nfsrvd_mkdir,
   99         nfsrvd_symlink,
  100         nfsrvd_mknod,
  101         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  102         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  103         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  104         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  105         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  106         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  107         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  108         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  109         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  110         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  111 };
  112 
  113 int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
  114     int, vnode_t , vnode_t , NFSPROC_T *,
  115     struct nfsexstuff *, struct nfsexstuff *) = {
  116         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  117         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  118         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  119         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  120         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  121         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  122         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  123         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  124         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  125         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  126         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  127         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  128         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  129         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  130         nfsrvd_rename,
  131         nfsrvd_link,
  132         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  133         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  134         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  135         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  136         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  137         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  138 };
  139 
  140 int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *,
  141     int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
  142         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  143         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  144         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  145         nfsrvd_access,
  146         nfsrvd_close,
  147         nfsrvd_commit,
  148         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  149         nfsrvd_delegpurge,
  150         nfsrvd_delegreturn,
  151         nfsrvd_getattr,
  152         nfsrvd_getfh,
  153         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  154         nfsrvd_lock,
  155         nfsrvd_lockt,
  156         nfsrvd_locku,
  157         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  158         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  159         nfsrvd_verify,
  160         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  161         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  162         nfsrvd_openconfirm,
  163         nfsrvd_opendowngrade,
  164         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  165         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  166         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  167         nfsrvd_read,
  168         nfsrvd_readdirplus,
  169         nfsrvd_readlink,
  170         nfsrvd_remove,
  171         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  172         nfsrvd_renew,
  173         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  174         (int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
  175         nfsrvd_secinfo,
  176         nfsrvd_setattr,
  177         nfsrvd_setclientid,
  178         nfsrvd_setclientidcfrm,
  179         nfsrvd_verify,
  180         nfsrvd_write,
  181         nfsrvd_releaselckown,
  182         nfsrvd_notsupp,
  183         nfsrvd_bindconnsess,
  184         nfsrvd_exchangeid,
  185         nfsrvd_createsession,
  186         nfsrvd_destroysession,
  187         nfsrvd_freestateid,
  188         nfsrvd_notsupp,
  189         nfsrvd_getdevinfo,
  190         nfsrvd_notsupp,
  191         nfsrvd_layoutcommit,
  192         nfsrvd_layoutget,
  193         nfsrvd_layoutreturn,
  194         nfsrvd_notsupp,
  195         nfsrvd_sequence,
  196         nfsrvd_notsupp,
  197         nfsrvd_teststateid,
  198         nfsrvd_notsupp,
  199         nfsrvd_destroyclientid,
  200         nfsrvd_reclaimcomplete,
  201 };
  202 
  203 int (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
  204     int, vnode_t , vnode_t *, fhandle_t *,
  205     NFSPROC_T *, struct nfsexstuff *) = {
  206         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  207         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  208         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  209         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  210         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  211         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  212         nfsrvd_mknod,
  213         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  214         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  215         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  216         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  217         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  218         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  219         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  220         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  221         nfsrvd_lookup,
  222         nfsrvd_lookup,
  223         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  224         nfsrvd_open,
  225         nfsrvd_openattr,
  226         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  227         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  228         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  229         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  230         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  231         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  232         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  233         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  234         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  235         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  236         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  237         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  238         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  239         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  240         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  241         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  242         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  243         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  244         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  245         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  246         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  247         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  248         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  249         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  250         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  251         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  252         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  253         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  254         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  255         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  256         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  257         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  258         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  259         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  260         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  261         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  262         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  263         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  264         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
  265 };
  266 
  267 int (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
  268     int, vnode_t , vnode_t , NFSPROC_T *,
  269     struct nfsexstuff *, struct nfsexstuff *) = {
  270         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  271         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  272         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  273         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  274         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  275         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  276         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  277         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  278         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  279         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  280         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  281         nfsrvd_link,
  282         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  283         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  284         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  285         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  286         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  287         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  288         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  289         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  290         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  291         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  292         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  293         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  294         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  295         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  296         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  297         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  298         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  299         nfsrvd_rename,
  300         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  301         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  302         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  303         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  304         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  305         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  306         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  307         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  308         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  309         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  310         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  311         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  312         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  313         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  314         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  315         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  316         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  317         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  318         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  319         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  320         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  321         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  322         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  323         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  324         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  325         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  326         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  327         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  328         (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
  329 };
  330 #endif  /* !APPLEKEXT */
  331 
  332 /*
  333  * Static array that defines which nfs rpc's are nonidempotent
  334  */
  335 static int nfsrv_nonidempotent[NFS_V3NPROCS] = {
  336         FALSE,
  337         FALSE,
  338         TRUE,
  339         FALSE,
  340         FALSE,
  341         FALSE,
  342         FALSE,
  343         TRUE,
  344         TRUE,
  345         TRUE,
  346         TRUE,
  347         TRUE,
  348         TRUE,
  349         TRUE,
  350         TRUE,
  351         TRUE,
  352         FALSE,
  353         FALSE,
  354         FALSE,
  355         FALSE,
  356         FALSE,
  357         FALSE,
  358 };
  359 
  360 /*
  361  * This static array indicates whether or not the RPC modifies the
  362  * file system.
  363  */
  364 int nfsrv_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
  365     1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
  366     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
  367 
  368 /* local functions */
  369 static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
  370     u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p);
  371 
  372 
  373 /*
  374  * This static array indicates which server procedures require the extra
  375  * arguments to return the current file handle for V2, 3.
  376  */
  377 static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
  378         1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
  379 
  380 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
  381 
  382 static int nfsv3to4op[NFS_V3NPROCS] = {
  383         NFSPROC_NULL,
  384         NFSV4OP_GETATTR,
  385         NFSV4OP_SETATTR,
  386         NFSV4OP_LOOKUP,
  387         NFSV4OP_ACCESS,
  388         NFSV4OP_READLINK,
  389         NFSV4OP_READ,
  390         NFSV4OP_WRITE,
  391         NFSV4OP_V3CREATE,
  392         NFSV4OP_MKDIR,
  393         NFSV4OP_SYMLINK,
  394         NFSV4OP_MKNOD,
  395         NFSV4OP_REMOVE,
  396         NFSV4OP_RMDIR,
  397         NFSV4OP_RENAME,
  398         NFSV4OP_LINK,
  399         NFSV4OP_READDIR,
  400         NFSV4OP_READDIRPLUS,
  401         NFSV4OP_FSSTAT,
  402         NFSV4OP_FSINFO,
  403         NFSV4OP_PATHCONF,
  404         NFSV4OP_COMMIT,
  405 };
  406 
  407 static struct mtx nfsrvd_statmtx;
  408 MTX_SYSINIT(nfsst, &nfsrvd_statmtx, "NFSstat", MTX_DEF);
  409 
  410 static void
  411 nfsrvd_statstart(int op, struct bintime *now)
  412 {
  413         if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
  414                 printf("%s: op %d invalid\n", __func__, op);
  415                 return;
  416         }
  417 
  418         mtx_lock(&nfsrvd_statmtx);
  419         if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) {
  420                 if (now != NULL)
  421                         nfsstatsv1.busyfrom = *now;
  422                 else
  423                         binuptime(&nfsstatsv1.busyfrom);
  424                 
  425         }
  426         nfsstatsv1.srvrpccnt[op]++;
  427         nfsstatsv1.srvstartcnt++;
  428         mtx_unlock(&nfsrvd_statmtx);
  429 
  430 }
  431 
  432 static void
  433 nfsrvd_statend(int op, uint64_t bytes, struct bintime *now,
  434     struct bintime *then)
  435 {
  436         struct bintime dt, lnow;
  437 
  438         if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) {
  439                 printf("%s: op %d invalid\n", __func__, op);
  440                 return;
  441         }
  442 
  443         if (now == NULL) {
  444                 now = &lnow;
  445                 binuptime(now);
  446         }
  447 
  448         mtx_lock(&nfsrvd_statmtx);
  449 
  450         nfsstatsv1.srvbytes[op] += bytes;
  451         nfsstatsv1.srvops[op]++;
  452 
  453         if (then != NULL) {
  454                 dt = *now;
  455                 bintime_sub(&dt, then);
  456                 bintime_add(&nfsstatsv1.srvduration[op], &dt);
  457         }
  458 
  459         dt = *now;
  460         bintime_sub(&dt, &nfsstatsv1.busyfrom);
  461         bintime_add(&nfsstatsv1.busytime, &dt);
  462         nfsstatsv1.busyfrom = *now;
  463 
  464         nfsstatsv1.srvdonecnt++;
  465 
  466         mtx_unlock(&nfsrvd_statmtx);
  467 }
  468 
  469 /*
  470  * Do an RPC. Basically, get the file handles translated to vnode pointers
  471  * and then call the appropriate server routine. The server routines are
  472  * split into groups, based on whether they use a file handle or file
  473  * handle plus name or ...
  474  * The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
  475  */
  476 APPLESTATIC void
  477 nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
  478     u_int32_t minorvers, NFSPROC_T *p)
  479 {
  480         int error = 0, lktype;
  481         vnode_t vp;
  482         mount_t mp = NULL;
  483         struct nfsrvfh fh;
  484         struct nfsexstuff nes;
  485 
  486         /*
  487          * Get a locked vnode for the first file handle
  488          */
  489         if (!(nd->nd_flag & ND_NFSV4)) {
  490                 KASSERT(nd->nd_repstat == 0, ("nfsrvd_dorpc"));
  491                 /*
  492                  * For NFSv3, if the malloc/mget allocation is near limits,
  493                  * return NFSERR_DELAY.
  494                  */
  495                 if ((nd->nd_flag & ND_NFSV3) && nfsrv_mallocmget_limit()) {
  496                         nd->nd_repstat = NFSERR_DELAY;
  497                         vp = NULL;
  498                 } else {
  499                         error = nfsrv_mtofh(nd, &fh);
  500                         if (error) {
  501                                 if (error != EBADRPC)
  502                                         printf("nfs dorpc err1=%d\n", error);
  503                                 nd->nd_repstat = NFSERR_GARBAGE;
  504                                 goto out;
  505                         }
  506                         if (nd->nd_procnum == NFSPROC_READ ||
  507                             nd->nd_procnum == NFSPROC_WRITE ||
  508                             nd->nd_procnum == NFSPROC_READDIR ||
  509                             nd->nd_procnum == NFSPROC_READDIRPLUS ||
  510                             nd->nd_procnum == NFSPROC_READLINK ||
  511                             nd->nd_procnum == NFSPROC_GETATTR ||
  512                             nd->nd_procnum == NFSPROC_ACCESS ||
  513                             nd->nd_procnum == NFSPROC_FSSTAT ||
  514                             nd->nd_procnum == NFSPROC_FSINFO)
  515                                 lktype = LK_SHARED;
  516                         else
  517                                 lktype = LK_EXCLUSIVE;
  518                         if (nd->nd_flag & ND_PUBLOOKUP)
  519                                 nfsd_fhtovp(nd, &nfs_pubfh, lktype, &vp, &nes,
  520                                     &mp, nfsrv_writerpc[nd->nd_procnum], p);
  521                         else
  522                                 nfsd_fhtovp(nd, &fh, lktype, &vp, &nes,
  523                                     &mp, nfsrv_writerpc[nd->nd_procnum], p);
  524                         if (nd->nd_repstat == NFSERR_PROGNOTV4)
  525                                 goto out;
  526                 }
  527         }
  528 
  529         /*
  530          * For V2 and 3, set the ND_SAVEREPLY flag for the recent request
  531          * cache, as required.
  532          * For V4, nfsrvd_compound() does this.
  533          */
  534         if (!(nd->nd_flag & ND_NFSV4) && nfsrv_nonidempotent[nd->nd_procnum])
  535                 nd->nd_flag |= ND_SAVEREPLY;
  536 
  537         nfsrvd_rephead(nd);
  538         /*
  539          * If nd_repstat is non-zero, just fill in the reply status
  540          * to complete the RPC reply for V2. Otherwise, you must do
  541          * the RPC.
  542          */
  543         if (nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
  544                 *nd->nd_errp = nfsd_errmap(nd);
  545                 nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], /*now*/ NULL);
  546                 nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
  547                    /*now*/ NULL, /*then*/ NULL);
  548                 if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
  549                         vn_finished_write(mp);
  550                 goto out;
  551         }
  552 
  553         /*
  554          * Now the procedure can be performed. For V4, nfsrvd_compound()
  555          * works through the sub-rpcs, otherwise just call the procedure.
  556          * The procedures are in three groups with different arguments.
  557          * The group is indicated by the value in nfs_retfh[].
  558          */
  559         if (nd->nd_flag & ND_NFSV4) {
  560                 nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
  561         } else {
  562                 struct bintime start_time;
  563 
  564                 binuptime(&start_time);
  565                 nfsrvd_statstart(nfsv3to4op[nd->nd_procnum], &start_time);
  566 
  567                 if (nfs_retfh[nd->nd_procnum] == 1) {
  568                         if (vp)
  569                                 NFSVOPUNLOCK(vp, 0);
  570                         error = (*(nfsrv3_procs1[nd->nd_procnum]))(nd, isdgram,
  571                             vp, NULL, (fhandle_t *)fh.nfsrvfh_data, p, &nes);
  572                 } else if (nfs_retfh[nd->nd_procnum] == 2) {
  573                         error = (*(nfsrv3_procs2[nd->nd_procnum]))(nd, isdgram,
  574                             vp, NULL, p, &nes, NULL);
  575                 } else {
  576                         error = (*(nfsrv3_procs0[nd->nd_procnum]))(nd, isdgram,
  577                             vp, p, &nes);
  578                 }
  579                 if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
  580                         vn_finished_write(mp);
  581 
  582                 nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
  583                     /*now*/ NULL, /*then*/ &start_time);
  584         }
  585         if (error) {
  586                 if (error != EBADRPC)
  587                         printf("nfs dorpc err2=%d\n", error);
  588                 nd->nd_repstat = NFSERR_GARBAGE;
  589         }
  590         *nd->nd_errp = nfsd_errmap(nd);
  591 
  592         /*
  593          * Don't cache certain reply status values.
  594          */
  595         if (nd->nd_repstat && (nd->nd_flag & ND_SAVEREPLY) &&
  596             (nd->nd_repstat == NFSERR_GARBAGE ||
  597              nd->nd_repstat == NFSERR_BADXDR ||
  598              nd->nd_repstat == NFSERR_MOVED ||
  599              nd->nd_repstat == NFSERR_DELAY ||
  600              nd->nd_repstat == NFSERR_BADSEQID ||
  601              nd->nd_repstat == NFSERR_RESOURCE ||
  602              nd->nd_repstat == NFSERR_SERVERFAULT ||
  603              nd->nd_repstat == NFSERR_STALECLIENTID ||
  604              nd->nd_repstat == NFSERR_STALESTATEID ||
  605              nd->nd_repstat == NFSERR_OLDSTATEID ||
  606              nd->nd_repstat == NFSERR_BADSTATEID ||
  607              nd->nd_repstat == NFSERR_GRACE ||
  608              nd->nd_repstat == NFSERR_NOGRACE))
  609                 nd->nd_flag &= ~ND_SAVEREPLY;
  610 
  611 out:
  612         NFSEXITCODE2(0, nd);
  613 }
  614 
  615 /*
  616  * Breaks down a compound RPC request and calls the server routines for
  617  * the subprocedures.
  618  * Some suboperations are performed directly here to simplify file handle<-->
  619  * vnode pointer handling.
  620  */
  621 static void
  622 nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
  623     int taglen, u_int32_t minorvers, NFSPROC_T *p)
  624 {
  625         int i, lktype, op, op0 = 0, statsinprog = 0;
  626         u_int32_t *tl;
  627         struct nfsclient *clp, *nclp;
  628         int numops, error = 0, igotlock;
  629         u_int32_t retops = 0, *retopsp = NULL, *repp;
  630         vnode_t vp, nvp, savevp;
  631         struct nfsrvfh fh;
  632         mount_t new_mp, temp_mp = NULL;
  633         struct ucred *credanon;
  634         struct nfsexstuff nes, vpnes, savevpnes;
  635         fsid_t cur_fsid, save_fsid;
  636         static u_int64_t compref = 0;
  637         struct bintime start_time;
  638 
  639         NFSVNO_EXINIT(&vpnes);
  640         NFSVNO_EXINIT(&savevpnes);
  641         /*
  642          * Put the seq# of the current compound RPC in nfsrv_descript.
  643          * (This is used by nfsrv_checkgetattr(), to see if the write
  644          *  delegation was created by the same compound RPC as the one
  645          *  with that Getattr in it.)
  646          * Don't worry about the 64bit number wrapping around. It ain't
  647          * gonna happen before this server gets shut down/rebooted.
  648          */
  649         nd->nd_compref = compref++;
  650 
  651         /*
  652          * Check for and optionally get a lock on the root. This lock means that
  653          * no nfsd will be fiddling with the V4 file system and state stuff. It
  654          * is required when the V4 root is being changed, the stable storage
  655          * restart file is being updated, or callbacks are being done.
  656          * When any of the nfsd are processing an NFSv4 compound RPC, they must
  657          * either hold a reference count (nfs_usecnt) or the lock. When
  658          * nfsrv_unlock() is called to release the lock, it can optionally
  659          * also get a reference count, which saves the need for a call to
  660          * nfsrv_getref() after nfsrv_unlock().
  661          */
  662         /*
  663          * First, check to see if we need to wait for an update lock.
  664          */
  665         igotlock = 0;
  666         NFSLOCKV4ROOTMUTEX();
  667         if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK)
  668                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
  669                     NFSV4ROOTLOCKMUTEXPTR, NULL);
  670         else
  671                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL,
  672                     NFSV4ROOTLOCKMUTEXPTR, NULL);
  673         NFSUNLOCKV4ROOTMUTEX();
  674         if (igotlock) {
  675                 /*
  676                  * If I got the lock, I can update the stable storage file.
  677                  * Done when the grace period is over or a client has long
  678                  * since expired.
  679                  */
  680                 nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK;
  681                 if ((nfsrv_stablefirst.nsf_flags &
  682                     (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER)
  683                         nfsrv_updatestable(p);
  684 
  685                 /*
  686                  * If at least one client has long since expired, search
  687                  * the client list for them, write a REVOKE record on the
  688                  * stable storage file and then remove them from the client
  689                  * list.
  690                  */
  691                 if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) {
  692                         nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT;
  693                         for (i = 0; i < nfsrv_clienthashsize; i++) {
  694                             LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash,
  695                                 nclp) {
  696                                 if (clp->lc_flags & LCL_EXPIREIT) {
  697                                     if (!LIST_EMPTY(&clp->lc_open) ||
  698                                         !LIST_EMPTY(&clp->lc_deleg))
  699                                         nfsrv_writestable(clp->lc_id,
  700                                             clp->lc_idlen, NFSNST_REVOKE, p);
  701                                     nfsrv_cleanclient(clp, p);
  702                                     nfsrv_freedeleglist(&clp->lc_deleg);
  703                                     nfsrv_freedeleglist(&clp->lc_olddeleg);
  704                                     LIST_REMOVE(clp, lc_hash);
  705                                     nfsrv_zapclient(clp, p);
  706                                 }
  707                             }
  708                         }
  709                 }
  710                 NFSLOCKV4ROOTMUTEX();
  711                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
  712                 NFSUNLOCKV4ROOTMUTEX();
  713         } else {
  714                 /*
  715                  * If we didn't get the lock, we need to get a refcnt,
  716                  * which also checks for and waits for the lock.
  717                  */
  718                 NFSLOCKV4ROOTMUTEX();
  719                 nfsv4_getref(&nfsv4rootfs_lock, NULL,
  720                     NFSV4ROOTLOCKMUTEXPTR, NULL);
  721                 NFSUNLOCKV4ROOTMUTEX();
  722         }
  723 
  724         /*
  725          * If flagged, search for open owners that haven't had any opens
  726          * for a long time.
  727          */
  728         if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) {
  729                 nfsrv_throwawayopens(p);
  730         }
  731 
  732         /* Do a CBLAYOUTRECALL callback if over the high water mark. */
  733         if (nfsrv_layoutcnt > nfsrv_layouthighwater)
  734                 nfsrv_recalloldlayout(p);
  735 
  736         savevp = vp = NULL;
  737         save_fsid.val[0] = save_fsid.val[1] = 0;
  738         cur_fsid.val[0] = cur_fsid.val[1] = 0;
  739 
  740         /* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
  741         if (taglen < 0) {
  742                 error = EBADRPC;
  743                 goto nfsmout;
  744         }
  745 
  746         (void) nfsm_strtom(nd, tag, taglen);
  747         NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
  748         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  749         if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
  750                 nd->nd_repstat = NFSERR_MINORVERMISMATCH;
  751         if (nd->nd_repstat)
  752                 numops = 0;
  753         else
  754                 numops = fxdr_unsigned(int, *tl);
  755         /*
  756          * Loop around doing the sub ops.
  757          * vp - is an unlocked vnode pointer for the CFH
  758          * savevp - is an unlocked vnode pointer for the SAVEDFH
  759          * (at some future date, it might turn out to be more appropriate
  760          *  to keep the file handles instead of vnode pointers?)
  761          * savevpnes and vpnes - are the export flags for the above.
  762          */
  763         for (i = 0; i < numops; i++) {
  764                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  765                 NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
  766                 *repp = *tl;
  767                 op = fxdr_unsigned(int, *tl);
  768                 NFSD_DEBUG(4, "op=%d\n", op);
  769                 if (op < NFSV4OP_ACCESS ||
  770                     (op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
  771                     (op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
  772                         nd->nd_repstat = NFSERR_OPILLEGAL;
  773                         *repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
  774                         *repp = nfsd_errmap(nd);
  775                         retops++;
  776                         break;
  777                 } else {
  778                         repp++;
  779                 }
  780 
  781                 binuptime(&start_time);
  782                 nfsrvd_statstart(op, &start_time);
  783                 statsinprog = 1;
  784 
  785                 if (i == 0)
  786                         op0 = op;
  787                 if (i == numops - 1)
  788                         nd->nd_flag |= ND_LASTOP;
  789 
  790                 /*
  791                  * Check for a referral on the current FH and, if so, return
  792                  * NFSERR_MOVED for all ops that allow it, except Getattr.
  793                  */
  794                 if (vp != NULL && op != NFSV4OP_GETATTR &&
  795                     nfsv4root_getreferral(vp, NULL, 0) != NULL &&
  796                     nfsrv_errmoved(op)) {
  797                         nd->nd_repstat = NFSERR_MOVED;
  798                         *repp = nfsd_errmap(nd);
  799                         retops++;
  800                         break;
  801                 }
  802 
  803                 /*
  804                  * For NFSv4.1, check for a Sequence Operation being first
  805                  * or one of the other allowed operations by itself.
  806                  */
  807                 if ((nd->nd_flag & ND_NFSV41) != 0) {
  808                         if (i != 0 && op == NFSV4OP_SEQUENCE)
  809                                 nd->nd_repstat = NFSERR_SEQUENCEPOS;
  810                         else if (i == 0 && op != NFSV4OP_SEQUENCE &&
  811                             op != NFSV4OP_EXCHANGEID &&
  812                             op != NFSV4OP_CREATESESSION &&
  813                             op != NFSV4OP_BINDCONNTOSESS &&
  814                             op != NFSV4OP_DESTROYCLIENTID &&
  815                             op != NFSV4OP_DESTROYSESSION)
  816                                 nd->nd_repstat = NFSERR_OPNOTINSESS;
  817                         else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
  818                                 nd->nd_repstat = NFSERR_NOTONLYOP;
  819                         if (nd->nd_repstat != 0) {
  820                                 *repp = nfsd_errmap(nd);
  821                                 retops++;
  822                                 break;
  823                         }
  824                 }
  825 
  826                 nd->nd_procnum = op;
  827                 /*
  828                  * If over flood level, reply NFSERR_RESOURCE, if at the first
  829                  * Op. (Since a client recovery from NFSERR_RESOURCE can get
  830                  * really nasty for certain Op sequences, I'll play it safe
  831                  * and only return the error at the beginning.) The cache
  832                  * will still function over flood level, but uses lots of
  833                  * mbufs.)
  834                  * If nfsrv_mallocmget_limit() returns True, the system is near
  835                  * to its limit for memory that malloc()/mget() can allocate.
  836                  */
  837                 if (i == 0 && (nd->nd_rp == NULL ||
  838                     nd->nd_rp->rc_refcnt == 0) &&
  839                     (nfsrv_mallocmget_limit() ||
  840                      nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
  841                         if (nfsrc_tcpsavedreplies > nfsrc_floodlevel)
  842                                 printf("nfsd server cache flooded, try "
  843                                     "increasing vfs.nfsd.tcphighwater\n");
  844                         nd->nd_repstat = NFSERR_RESOURCE;
  845                         *repp = nfsd_errmap(nd);
  846                         if (op == NFSV4OP_SETATTR) {
  847                                 /*
  848                                  * Setattr replies require a bitmap.
  849                                  * even for errors like these.
  850                                  */
  851                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  852                                 *tl = 0;
  853                         }
  854                         retops++;
  855                         break;
  856                 }
  857                 if (nfsv4_opflag[op].savereply)
  858                         nd->nd_flag |= ND_SAVEREPLY;
  859                 switch (op) {
  860                 case NFSV4OP_PUTFH:
  861                         error = nfsrv_mtofh(nd, &fh);
  862                         if (error)
  863                                 goto nfsmout;
  864                         if (!nd->nd_repstat)
  865                                 nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
  866                                     NULL, 0, p);
  867                         /* For now, allow this for non-export FHs */
  868                         if (!nd->nd_repstat) {
  869                                 if (vp)
  870                                         vrele(vp);
  871                                 vp = nvp;
  872                                 cur_fsid = vp->v_mount->mnt_stat.f_fsid;
  873                                 NFSVOPUNLOCK(vp, 0);
  874                                 vpnes = nes;
  875                         }
  876                         break;
  877                 case NFSV4OP_PUTPUBFH:
  878                         if (nfs_pubfhset)
  879                             nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
  880                                 &nes, NULL, 0, p);
  881                         else
  882                             nd->nd_repstat = NFSERR_NOFILEHANDLE;
  883                         if (!nd->nd_repstat) {
  884                                 if (vp)
  885                                         vrele(vp);
  886                                 vp = nvp;
  887                                 cur_fsid = vp->v_mount->mnt_stat.f_fsid;
  888                                 NFSVOPUNLOCK(vp, 0);
  889                                 vpnes = nes;
  890                         }
  891                         break;
  892                 case NFSV4OP_PUTROOTFH:
  893                         if (nfs_rootfhset) {
  894                                 nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
  895                                     &nes, NULL, 0, p);
  896                                 if (!nd->nd_repstat) {
  897                                         if (vp)
  898                                                 vrele(vp);
  899                                         vp = nvp;
  900                                         cur_fsid = vp->v_mount->mnt_stat.f_fsid;
  901                                         NFSVOPUNLOCK(vp, 0);
  902                                         vpnes = nes;
  903                                 }
  904                         } else
  905                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
  906                         break;
  907                 case NFSV4OP_SAVEFH:
  908                         if (vp && NFSVNO_EXPORTED(&vpnes)) {
  909                                 nd->nd_repstat = 0;
  910                                 /* If vp == savevp, a no-op */
  911                                 if (vp != savevp) {
  912                                         if (savevp)
  913                                                 vrele(savevp);
  914                                         VREF(vp);
  915                                         savevp = vp;
  916                                         savevpnes = vpnes;
  917                                         save_fsid = cur_fsid;
  918                                 }
  919                                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
  920                                         nd->nd_savedcurstateid =
  921                                             nd->nd_curstateid;
  922                                         nd->nd_flag |= ND_SAVEDCURSTATEID;
  923                                 }
  924                         } else {
  925                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
  926                         }
  927                         break;
  928                 case NFSV4OP_RESTOREFH:
  929                         if (savevp) {
  930                                 nd->nd_repstat = 0;
  931                                 /* If vp == savevp, a no-op */
  932                                 if (vp != savevp) {
  933                                         VREF(savevp);
  934                                         vrele(vp);
  935                                         vp = savevp;
  936                                         vpnes = savevpnes;
  937                                         cur_fsid = save_fsid;
  938                                 }
  939                                 if ((nd->nd_flag & ND_SAVEDCURSTATEID) != 0) {
  940                                         nd->nd_curstateid =
  941                                             nd->nd_savedcurstateid;
  942                                         nd->nd_flag |= ND_CURSTATEID;
  943                                 }
  944                         } else {
  945                                 nd->nd_repstat = NFSERR_RESTOREFH;
  946                         }
  947                         break;
  948                 default:
  949                     /*
  950                      * Allow a Lookup, Getattr, GetFH, Secinfo on an
  951                      * non-exported directory if
  952                      * nfs_rootfhset. Do I need to allow any other Ops?
  953                      * (You can only have a non-exported vpnes if
  954                      *  nfs_rootfhset is true. See nfsd_fhtovp())
  955                      * Allow AUTH_SYS to be used for file systems
  956                      * exported GSS only for certain Ops, to allow
  957                      * clients to do mounts more easily.
  958                      */
  959                     if (nfsv4_opflag[op].needscfh && vp) {
  960                         if (!NFSVNO_EXPORTED(&vpnes) &&
  961                             op != NFSV4OP_LOOKUP &&
  962                             op != NFSV4OP_GETATTR &&
  963                             op != NFSV4OP_GETFH &&
  964                             op != NFSV4OP_ACCESS &&
  965                             op != NFSV4OP_READLINK &&
  966                             op != NFSV4OP_SECINFO)
  967                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
  968                         else if (nfsvno_testexp(nd, &vpnes) &&
  969                             op != NFSV4OP_LOOKUP &&
  970                             op != NFSV4OP_GETFH &&
  971                             op != NFSV4OP_GETATTR &&
  972                             op != NFSV4OP_SECINFO)
  973                                 nd->nd_repstat = NFSERR_WRONGSEC;
  974                         if (nd->nd_repstat) {
  975                                 if (op == NFSV4OP_SETATTR) {
  976                                     /*
  977                                      * Setattr reply requires a bitmap
  978                                      * even for errors like these.
  979                                      */
  980                                     NFSM_BUILD(tl, u_int32_t *,
  981                                         NFSX_UNSIGNED);
  982                                     *tl = 0;
  983                                 }
  984                                 break;
  985                         }
  986                     }
  987                     if (nfsv4_opflag[op].retfh == 1) {
  988                         if (!vp) {
  989                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
  990                                 break;
  991                         }
  992                         VREF(vp);
  993                         if (nfsv4_opflag[op].modifyfs)
  994                                 vn_start_write(vp, &temp_mp, V_WAIT);
  995                         error = (*(nfsrv4_ops1[op]))(nd, isdgram, vp,
  996                             &nvp, (fhandle_t *)fh.nfsrvfh_data, p, &vpnes);
  997                         if (!error && !nd->nd_repstat) {
  998                             if (op == NFSV4OP_LOOKUP || op == NFSV4OP_LOOKUPP) {
  999                                 new_mp = nvp->v_mount;
 1000                                 if (cur_fsid.val[0] !=
 1001                                     new_mp->mnt_stat.f_fsid.val[0] ||
 1002                                     cur_fsid.val[1] !=
 1003                                     new_mp->mnt_stat.f_fsid.val[1]) {
 1004                                     /* crossed a server mount point */
 1005                                     nd->nd_repstat = nfsvno_checkexp(new_mp,
 1006                                         nd->nd_nam, &nes, &credanon);
 1007                                     if (!nd->nd_repstat)
 1008                                         nd->nd_repstat = nfsd_excred(nd,
 1009                                             &nes, credanon);
 1010                                     if (credanon != NULL)
 1011                                         crfree(credanon);
 1012                                     if (!nd->nd_repstat) {
 1013                                         vpnes = nes;
 1014                                         cur_fsid = new_mp->mnt_stat.f_fsid;
 1015                                     }
 1016                                 }
 1017                                 /* Lookup ops return a locked vnode */
 1018                                 NFSVOPUNLOCK(nvp, 0);
 1019                             }
 1020                             if (!nd->nd_repstat) {
 1021                                     vrele(vp);
 1022                                     vp = nvp;
 1023                             } else
 1024                                     vrele(nvp);
 1025                         }
 1026                         if (nfsv4_opflag[op].modifyfs)
 1027                                 vn_finished_write(temp_mp);
 1028                     } else if (nfsv4_opflag[op].retfh == 2) {
 1029                         if (vp == NULL || savevp == NULL) {
 1030                                 nd->nd_repstat = NFSERR_NOFILEHANDLE;
 1031                                 break;
 1032                         } else if (cur_fsid.val[0] != save_fsid.val[0] ||
 1033                             cur_fsid.val[1] != save_fsid.val[1]) {
 1034                                 nd->nd_repstat = NFSERR_XDEV;
 1035                                 break;
 1036                         }
 1037                         if (nfsv4_opflag[op].modifyfs)
 1038                                 vn_start_write(savevp, &temp_mp, V_WAIT);
 1039                         if (NFSVOPLOCK(savevp, LK_EXCLUSIVE) == 0) {
 1040                                 VREF(vp);
 1041                                 VREF(savevp);
 1042                                 error = (*(nfsrv4_ops2[op]))(nd, isdgram,
 1043                                     savevp, vp, p, &savevpnes, &vpnes);
 1044                         } else
 1045                                 nd->nd_repstat = NFSERR_PERM;
 1046                         if (nfsv4_opflag[op].modifyfs)
 1047                                 vn_finished_write(temp_mp);
 1048                     } else {
 1049                         if (nfsv4_opflag[op].retfh != 0)
 1050                                 panic("nfsrvd_compound");
 1051                         if (nfsv4_opflag[op].needscfh) {
 1052                                 if (vp != NULL) {
 1053                                         lktype = nfsv4_opflag[op].lktype;
 1054                                         if (nfsv4_opflag[op].modifyfs) {
 1055                                                 vn_start_write(vp, &temp_mp,
 1056                                                     V_WAIT);
 1057                                                 if (op == NFSV4OP_WRITE &&
 1058                                                     MNT_SHARED_WRITES(temp_mp))
 1059                                                         lktype = LK_SHARED;
 1060                                         }
 1061                                         if (NFSVOPLOCK(vp, lktype) == 0)
 1062                                                 VREF(vp);
 1063                                         else
 1064                                                 nd->nd_repstat = NFSERR_PERM;
 1065                                 } else {
 1066                                         nd->nd_repstat = NFSERR_NOFILEHANDLE;
 1067                                         if (op == NFSV4OP_SETATTR) {
 1068                                                 /*
 1069                                                  * Setattr reply requires a
 1070                                                  * bitmap even for errors like
 1071                                                  * these.
 1072                                                  */
 1073                                                 NFSM_BUILD(tl, u_int32_t *,
 1074                                                     NFSX_UNSIGNED);
 1075                                                 *tl = 0;
 1076                                         }
 1077                                         break;
 1078                                 }
 1079                                 if (nd->nd_repstat == 0)
 1080                                         error = (*(nfsrv4_ops0[op]))(nd,
 1081                                             isdgram, vp, p, &vpnes);
 1082                                 if (nfsv4_opflag[op].modifyfs)
 1083                                         vn_finished_write(temp_mp);
 1084                         } else {
 1085                                 error = (*(nfsrv4_ops0[op]))(nd, isdgram,
 1086                                     NULL, p, &vpnes);
 1087                         }
 1088                     }
 1089                 }
 1090                 if (error) {
 1091                         if (error == EBADRPC || error == NFSERR_BADXDR) {
 1092                                 nd->nd_repstat = NFSERR_BADXDR;
 1093                         } else {
 1094                                 nd->nd_repstat = error;
 1095                                 printf("nfsv4 comperr0=%d\n", error);
 1096                         }
 1097                         error = 0;
 1098                 }
 1099 
 1100                 if (statsinprog != 0) {
 1101                         nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
 1102                             /*then*/ &start_time);
 1103                         statsinprog = 0;
 1104                 }
 1105 
 1106                 retops++;
 1107                 if (nd->nd_repstat) {
 1108                         *repp = nfsd_errmap(nd);
 1109                         break;
 1110                 } else {
 1111                         *repp = 0;      /* NFS4_OK */
 1112                 }
 1113         }
 1114 nfsmout:
 1115         if (statsinprog != 0) {
 1116                 nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
 1117                     /*then*/ &start_time);
 1118                 statsinprog = 0;
 1119         }
 1120         if (error) {
 1121                 if (error == EBADRPC || error == NFSERR_BADXDR)
 1122                         nd->nd_repstat = NFSERR_BADXDR;
 1123                 else
 1124                         printf("nfsv4 comperr1=%d\n", error);
 1125         }
 1126         if (taglen == -1) {
 1127                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1128                 *tl++ = 0;
 1129                 *tl = 0;
 1130         } else {
 1131                 *retopsp = txdr_unsigned(retops);
 1132         }
 1133         if (vp)
 1134                 vrele(vp);
 1135         if (savevp)
 1136                 vrele(savevp);
 1137         NFSLOCKV4ROOTMUTEX();
 1138         nfsv4_relref(&nfsv4rootfs_lock);
 1139         NFSUNLOCKV4ROOTMUTEX();
 1140 
 1141         NFSEXITCODE2(0, nd);
 1142 }

Cache object: 45e335ace276f17f52f0fcee344ea9fd


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.