Home | History | Annotate | Line # | Download | only in nfs
nfs_subs.c revision 1.222.12.1
      1  1.222.12.1     rmind /*	$NetBSD: nfs_subs.c,v 1.222.12.1 2014/05/18 17:46:14 rmind Exp $	*/
      2        1.14       cgd 
      3         1.1       cgd /*
      4        1.12   mycroft  * Copyright (c) 1989, 1993
      5        1.12   mycroft  *	The Regents of the University of California.  All rights reserved.
      6         1.1       cgd  *
      7         1.1       cgd  * This code is derived from software contributed to Berkeley by
      8         1.1       cgd  * Rick Macklem at The University of Guelph.
      9         1.1       cgd  *
     10         1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11         1.1       cgd  * modification, are permitted provided that the following conditions
     12         1.1       cgd  * are met:
     13         1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14         1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15         1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16         1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17         1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18       1.127       agc  * 3. Neither the name of the University nor the names of its contributors
     19         1.1       cgd  *    may be used to endorse or promote products derived from this software
     20         1.1       cgd  *    without specific prior written permission.
     21         1.1       cgd  *
     22         1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23         1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24         1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25         1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26         1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27         1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28         1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29         1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30         1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31         1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32         1.1       cgd  * SUCH DAMAGE.
     33         1.1       cgd  *
     34        1.25      fvdl  *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
     35         1.1       cgd  */
     36         1.1       cgd 
     37        1.83      fvdl /*
     38        1.83      fvdl  * Copyright 2000 Wasabi Systems, Inc.
     39        1.83      fvdl  * All rights reserved.
     40        1.83      fvdl  *
     41        1.83      fvdl  * Written by Frank van der Linden for Wasabi Systems, Inc.
     42        1.83      fvdl  *
     43        1.83      fvdl  * Redistribution and use in source and binary forms, with or without
     44        1.83      fvdl  * modification, are permitted provided that the following conditions
     45        1.83      fvdl  * are met:
     46        1.83      fvdl  * 1. Redistributions of source code must retain the above copyright
     47        1.83      fvdl  *    notice, this list of conditions and the following disclaimer.
     48        1.83      fvdl  * 2. Redistributions in binary form must reproduce the above copyright
     49        1.83      fvdl  *    notice, this list of conditions and the following disclaimer in the
     50        1.83      fvdl  *    documentation and/or other materials provided with the distribution.
     51        1.83      fvdl  * 3. All advertising materials mentioning features or use of this software
     52        1.83      fvdl  *    must display the following acknowledgement:
     53        1.83      fvdl  *      This product includes software developed for the NetBSD Project by
     54        1.83      fvdl  *      Wasabi Systems, Inc.
     55        1.83      fvdl  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     56        1.83      fvdl  *    or promote products derived from this software without specific prior
     57        1.83      fvdl  *    written permission.
     58        1.83      fvdl  *
     59        1.83      fvdl  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     60        1.83      fvdl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     61        1.83      fvdl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     62        1.83      fvdl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     63        1.83      fvdl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     64        1.83      fvdl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     65        1.83      fvdl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     66        1.83      fvdl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     67        1.83      fvdl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     68        1.83      fvdl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     69        1.83      fvdl  * POSSIBILITY OF SUCH DAMAGE.
     70        1.83      fvdl  */
     71        1.99     lukem 
     72        1.99     lukem #include <sys/cdefs.h>
     73  1.222.12.1     rmind __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.222.12.1 2014/05/18 17:46:14 rmind Exp $");
     74        1.83      fvdl 
     75       1.210        ad #ifdef _KERNEL_OPT
     76        1.82     bjh21 #include "opt_nfs.h"
     77       1.210        ad #endif
     78        1.25      fvdl 
     79         1.1       cgd /*
     80         1.1       cgd  * These functions support the macros and help fiddle mbuf chains for
     81         1.1       cgd  * the nfs op functions. They do things like create the rpc header and
     82         1.1       cgd  * copy data between mbuf chains and uio lists.
     83         1.1       cgd  */
     84         1.9   mycroft #include <sys/param.h>
     85         1.9   mycroft #include <sys/proc.h>
     86         1.9   mycroft #include <sys/systm.h>
     87         1.9   mycroft #include <sys/kernel.h>
     88       1.196      yamt #include <sys/kmem.h>
     89         1.9   mycroft #include <sys/mount.h>
     90         1.9   mycroft #include <sys/vnode.h>
     91         1.9   mycroft #include <sys/namei.h>
     92         1.9   mycroft #include <sys/mbuf.h>
     93        1.12   mycroft #include <sys/socket.h>
     94        1.12   mycroft #include <sys/stat.h>
     95        1.98      fvdl #include <sys/filedesc.h>
     96        1.30      fvdl #include <sys/time.h>
     97        1.43      fvdl #include <sys/dirent.h>
     98       1.155   thorpej #include <sys/once.h>
     99       1.162      elad #include <sys/kauth.h>
    100       1.207     pooka #include <sys/atomic.h>
    101       1.222       tls #include <sys/cprng.h>
    102         1.1       cgd 
    103       1.220  uebayasi #include <uvm/uvm.h>
    104        1.51       mrg 
    105         1.9   mycroft #include <nfs/rpcv2.h>
    106        1.25      fvdl #include <nfs/nfsproto.h>
    107         1.9   mycroft #include <nfs/nfsnode.h>
    108         1.9   mycroft #include <nfs/nfs.h>
    109         1.9   mycroft #include <nfs/xdr_subs.h>
    110         1.9   mycroft #include <nfs/nfsm_subs.h>
    111        1.12   mycroft #include <nfs/nfsmount.h>
    112        1.12   mycroft #include <nfs/nfsrtt.h>
    113        1.24  christos #include <nfs/nfs_var.h>
    114        1.12   mycroft 
    115        1.12   mycroft #include <miscfs/specfs/specdev.h>
    116        1.24  christos 
    117        1.12   mycroft #include <netinet/in.h>
    118         1.1       cgd 
    119       1.207     pooka static u_int32_t nfs_xid;
    120       1.207     pooka 
    121       1.218  christos int nuidhash_max = NFS_MAXUIDHASH;
    122         1.1       cgd /*
    123         1.1       cgd  * Data items converted to xdr at startup, since they are constant
    124         1.1       cgd  * This is kinda hokey, but may save a little time doing byte swaps
    125         1.1       cgd  */
    126        1.22       cgd u_int32_t nfs_xdrneg1;
    127        1.22       cgd u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
    128        1.25      fvdl 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
    129        1.12   mycroft 	rpc_auth_kerb;
    130       1.179      yamt u_int32_t nfs_prog, nfs_true, nfs_false;
    131        1.12   mycroft 
    132         1.1       cgd /* And other global data */
    133        1.90  jdolecek const nfstype nfsv2_type[9] =
    134        1.90  jdolecek 	{ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
    135        1.90  jdolecek const nfstype nfsv3_type[9] =
    136        1.90  jdolecek 	{ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
    137        1.90  jdolecek const enum vtype nv2tov_type[8] =
    138        1.90  jdolecek 	{ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
    139        1.90  jdolecek const enum vtype nv3tov_type[8] =
    140        1.90  jdolecek 	{ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
    141        1.25      fvdl int nfs_ticks;
    142       1.108  christos 
    143        1.35   thorpej /* NFS client/server stats. */
    144        1.35   thorpej struct nfsstats nfsstats;
    145        1.35   thorpej 
    146        1.25      fvdl /*
    147        1.25      fvdl  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
    148        1.25      fvdl  */
    149        1.90  jdolecek const int nfsv3_procid[NFS_NPROCS] = {
    150        1.25      fvdl 	NFSPROC_NULL,
    151        1.25      fvdl 	NFSPROC_GETATTR,
    152        1.25      fvdl 	NFSPROC_SETATTR,
    153        1.25      fvdl 	NFSPROC_NOOP,
    154        1.25      fvdl 	NFSPROC_LOOKUP,
    155        1.25      fvdl 	NFSPROC_READLINK,
    156        1.25      fvdl 	NFSPROC_READ,
    157        1.25      fvdl 	NFSPROC_NOOP,
    158        1.25      fvdl 	NFSPROC_WRITE,
    159        1.25      fvdl 	NFSPROC_CREATE,
    160        1.25      fvdl 	NFSPROC_REMOVE,
    161        1.25      fvdl 	NFSPROC_RENAME,
    162        1.25      fvdl 	NFSPROC_LINK,
    163        1.25      fvdl 	NFSPROC_SYMLINK,
    164        1.25      fvdl 	NFSPROC_MKDIR,
    165        1.25      fvdl 	NFSPROC_RMDIR,
    166        1.25      fvdl 	NFSPROC_READDIR,
    167        1.25      fvdl 	NFSPROC_FSSTAT,
    168        1.25      fvdl 	NFSPROC_NOOP,
    169        1.25      fvdl 	NFSPROC_NOOP,
    170        1.25      fvdl 	NFSPROC_NOOP,
    171        1.25      fvdl 	NFSPROC_NOOP,
    172        1.25      fvdl 	NFSPROC_NOOP
    173        1.25      fvdl };
    174        1.25      fvdl 
    175        1.25      fvdl /*
    176        1.25      fvdl  * and the reverse mapping from generic to Version 2 procedure numbers
    177        1.25      fvdl  */
    178        1.90  jdolecek const int nfsv2_procid[NFS_NPROCS] = {
    179        1.25      fvdl 	NFSV2PROC_NULL,
    180        1.25      fvdl 	NFSV2PROC_GETATTR,
    181        1.25      fvdl 	NFSV2PROC_SETATTR,
    182        1.25      fvdl 	NFSV2PROC_LOOKUP,
    183        1.25      fvdl 	NFSV2PROC_NOOP,
    184        1.25      fvdl 	NFSV2PROC_READLINK,
    185        1.25      fvdl 	NFSV2PROC_READ,
    186        1.25      fvdl 	NFSV2PROC_WRITE,
    187        1.25      fvdl 	NFSV2PROC_CREATE,
    188        1.25      fvdl 	NFSV2PROC_MKDIR,
    189        1.25      fvdl 	NFSV2PROC_SYMLINK,
    190        1.25      fvdl 	NFSV2PROC_CREATE,
    191        1.25      fvdl 	NFSV2PROC_REMOVE,
    192        1.25      fvdl 	NFSV2PROC_RMDIR,
    193        1.25      fvdl 	NFSV2PROC_RENAME,
    194        1.25      fvdl 	NFSV2PROC_LINK,
    195        1.25      fvdl 	NFSV2PROC_READDIR,
    196        1.25      fvdl 	NFSV2PROC_NOOP,
    197        1.25      fvdl 	NFSV2PROC_STATFS,
    198        1.25      fvdl 	NFSV2PROC_NOOP,
    199        1.25      fvdl 	NFSV2PROC_NOOP,
    200        1.25      fvdl 	NFSV2PROC_NOOP,
    201        1.25      fvdl 	NFSV2PROC_NOOP,
    202        1.25      fvdl };
    203        1.25      fvdl 
    204        1.25      fvdl /*
    205        1.25      fvdl  * Maps errno values to nfs error numbers.
    206        1.25      fvdl  * Use NFSERR_IO as the catch all for ones not specifically defined in
    207        1.25      fvdl  * RFC 1094.
    208        1.25      fvdl  */
    209        1.90  jdolecek static const u_char nfsrv_v2errmap[ELAST] = {
    210        1.25      fvdl   NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    211        1.25      fvdl   NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    212        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
    213        1.25      fvdl   NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
    214        1.25      fvdl   NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    215        1.25      fvdl   NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
    216        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    217        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    218        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    219        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    220        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    221        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    222        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
    223        1.25      fvdl   NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
    224        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    225        1.25      fvdl   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
    226        1.52     mikel   NFSERR_IO,	NFSERR_IO,
    227        1.25      fvdl };
    228        1.25      fvdl 
    229        1.25      fvdl /*
    230        1.25      fvdl  * Maps errno values to nfs error numbers.
    231        1.25      fvdl  * Although it is not obvious whether or not NFS clients really care if
    232        1.25      fvdl  * a returned error value is in the specified list for the procedure, the
    233        1.25      fvdl  * safest thing to do is filter them appropriately. For Version 2, the
    234        1.25      fvdl  * X/Open XNFS document is the only specification that defines error values
    235        1.25      fvdl  * for each RPC (The RFC simply lists all possible error values for all RPCs),
    236        1.25      fvdl  * so I have decided to not do this for Version 2.
    237        1.25      fvdl  * The first entry is the default error return and the rest are the valid
    238        1.25      fvdl  * errors for that RPC in increasing numeric order.
    239        1.25      fvdl  */
    240        1.90  jdolecek static const short nfsv3err_null[] = {
    241        1.25      fvdl 	0,
    242        1.25      fvdl 	0,
    243        1.25      fvdl };
    244        1.25      fvdl 
    245        1.90  jdolecek static const short nfsv3err_getattr[] = {
    246        1.25      fvdl 	NFSERR_IO,
    247        1.25      fvdl 	NFSERR_IO,
    248        1.25      fvdl 	NFSERR_STALE,
    249        1.25      fvdl 	NFSERR_BADHANDLE,
    250        1.25      fvdl 	NFSERR_SERVERFAULT,
    251        1.25      fvdl 	0,
    252        1.25      fvdl };
    253        1.25      fvdl 
    254        1.90  jdolecek static const short nfsv3err_setattr[] = {
    255        1.25      fvdl 	NFSERR_IO,
    256        1.25      fvdl 	NFSERR_PERM,
    257        1.25      fvdl 	NFSERR_IO,
    258        1.25      fvdl 	NFSERR_ACCES,
    259        1.25      fvdl 	NFSERR_INVAL,
    260        1.25      fvdl 	NFSERR_NOSPC,
    261        1.25      fvdl 	NFSERR_ROFS,
    262        1.25      fvdl 	NFSERR_DQUOT,
    263        1.25      fvdl 	NFSERR_STALE,
    264        1.25      fvdl 	NFSERR_BADHANDLE,
    265        1.25      fvdl 	NFSERR_NOT_SYNC,
    266        1.25      fvdl 	NFSERR_SERVERFAULT,
    267        1.25      fvdl 	0,
    268        1.25      fvdl };
    269        1.25      fvdl 
    270        1.90  jdolecek static const short nfsv3err_lookup[] = {
    271        1.25      fvdl 	NFSERR_IO,
    272        1.25      fvdl 	NFSERR_NOENT,
    273        1.25      fvdl 	NFSERR_IO,
    274        1.25      fvdl 	NFSERR_ACCES,
    275        1.25      fvdl 	NFSERR_NOTDIR,
    276        1.25      fvdl 	NFSERR_NAMETOL,
    277        1.25      fvdl 	NFSERR_STALE,
    278        1.25      fvdl 	NFSERR_BADHANDLE,
    279        1.25      fvdl 	NFSERR_SERVERFAULT,
    280        1.25      fvdl 	0,
    281        1.25      fvdl };
    282        1.25      fvdl 
    283        1.90  jdolecek static const short nfsv3err_access[] = {
    284        1.25      fvdl 	NFSERR_IO,
    285        1.25      fvdl 	NFSERR_IO,
    286        1.25      fvdl 	NFSERR_STALE,
    287        1.25      fvdl 	NFSERR_BADHANDLE,
    288        1.25      fvdl 	NFSERR_SERVERFAULT,
    289        1.25      fvdl 	0,
    290        1.25      fvdl };
    291        1.25      fvdl 
    292        1.90  jdolecek static const short nfsv3err_readlink[] = {
    293        1.25      fvdl 	NFSERR_IO,
    294        1.25      fvdl 	NFSERR_IO,
    295        1.25      fvdl 	NFSERR_ACCES,
    296        1.25      fvdl 	NFSERR_INVAL,
    297        1.25      fvdl 	NFSERR_STALE,
    298        1.25      fvdl 	NFSERR_BADHANDLE,
    299        1.25      fvdl 	NFSERR_NOTSUPP,
    300        1.25      fvdl 	NFSERR_SERVERFAULT,
    301        1.25      fvdl 	0,
    302        1.25      fvdl };
    303        1.25      fvdl 
    304        1.90  jdolecek static const short nfsv3err_read[] = {
    305        1.25      fvdl 	NFSERR_IO,
    306        1.25      fvdl 	NFSERR_IO,
    307        1.25      fvdl 	NFSERR_NXIO,
    308        1.25      fvdl 	NFSERR_ACCES,
    309        1.25      fvdl 	NFSERR_INVAL,
    310        1.25      fvdl 	NFSERR_STALE,
    311        1.25      fvdl 	NFSERR_BADHANDLE,
    312        1.25      fvdl 	NFSERR_SERVERFAULT,
    313        1.67      fvdl 	NFSERR_JUKEBOX,
    314        1.25      fvdl 	0,
    315        1.25      fvdl };
    316        1.25      fvdl 
    317        1.90  jdolecek static const short nfsv3err_write[] = {
    318        1.25      fvdl 	NFSERR_IO,
    319        1.25      fvdl 	NFSERR_IO,
    320        1.25      fvdl 	NFSERR_ACCES,
    321        1.25      fvdl 	NFSERR_INVAL,
    322        1.25      fvdl 	NFSERR_FBIG,
    323        1.25      fvdl 	NFSERR_NOSPC,
    324        1.25      fvdl 	NFSERR_ROFS,
    325        1.25      fvdl 	NFSERR_DQUOT,
    326        1.25      fvdl 	NFSERR_STALE,
    327        1.25      fvdl 	NFSERR_BADHANDLE,
    328        1.25      fvdl 	NFSERR_SERVERFAULT,
    329        1.68      fvdl 	NFSERR_JUKEBOX,
    330        1.25      fvdl 	0,
    331        1.25      fvdl };
    332        1.25      fvdl 
    333        1.90  jdolecek static const short nfsv3err_create[] = {
    334        1.25      fvdl 	NFSERR_IO,
    335        1.25      fvdl 	NFSERR_IO,
    336        1.25      fvdl 	NFSERR_ACCES,
    337        1.25      fvdl 	NFSERR_EXIST,
    338        1.25      fvdl 	NFSERR_NOTDIR,
    339        1.25      fvdl 	NFSERR_NOSPC,
    340        1.25      fvdl 	NFSERR_ROFS,
    341        1.25      fvdl 	NFSERR_NAMETOL,
    342        1.25      fvdl 	NFSERR_DQUOT,
    343        1.25      fvdl 	NFSERR_STALE,
    344        1.25      fvdl 	NFSERR_BADHANDLE,
    345        1.25      fvdl 	NFSERR_NOTSUPP,
    346        1.25      fvdl 	NFSERR_SERVERFAULT,
    347        1.25      fvdl 	0,
    348        1.25      fvdl };
    349        1.25      fvdl 
    350        1.90  jdolecek static const short nfsv3err_mkdir[] = {
    351        1.25      fvdl 	NFSERR_IO,
    352        1.25      fvdl 	NFSERR_IO,
    353        1.25      fvdl 	NFSERR_ACCES,
    354        1.25      fvdl 	NFSERR_EXIST,
    355        1.25      fvdl 	NFSERR_NOTDIR,
    356        1.25      fvdl 	NFSERR_NOSPC,
    357        1.25      fvdl 	NFSERR_ROFS,
    358        1.25      fvdl 	NFSERR_NAMETOL,
    359        1.25      fvdl 	NFSERR_DQUOT,
    360        1.25      fvdl 	NFSERR_STALE,
    361        1.25      fvdl 	NFSERR_BADHANDLE,
    362        1.25      fvdl 	NFSERR_NOTSUPP,
    363        1.25      fvdl 	NFSERR_SERVERFAULT,
    364        1.25      fvdl 	0,
    365        1.25      fvdl };
    366        1.25      fvdl 
    367        1.90  jdolecek static const short nfsv3err_symlink[] = {
    368        1.25      fvdl 	NFSERR_IO,
    369        1.25      fvdl 	NFSERR_IO,
    370        1.25      fvdl 	NFSERR_ACCES,
    371        1.25      fvdl 	NFSERR_EXIST,
    372        1.25      fvdl 	NFSERR_NOTDIR,
    373        1.25      fvdl 	NFSERR_NOSPC,
    374        1.25      fvdl 	NFSERR_ROFS,
    375        1.25      fvdl 	NFSERR_NAMETOL,
    376        1.25      fvdl 	NFSERR_DQUOT,
    377        1.25      fvdl 	NFSERR_STALE,
    378        1.25      fvdl 	NFSERR_BADHANDLE,
    379        1.25      fvdl 	NFSERR_NOTSUPP,
    380        1.25      fvdl 	NFSERR_SERVERFAULT,
    381        1.25      fvdl 	0,
    382        1.25      fvdl };
    383        1.25      fvdl 
    384        1.90  jdolecek static const short nfsv3err_mknod[] = {
    385        1.25      fvdl 	NFSERR_IO,
    386        1.25      fvdl 	NFSERR_IO,
    387        1.25      fvdl 	NFSERR_ACCES,
    388        1.25      fvdl 	NFSERR_EXIST,
    389        1.25      fvdl 	NFSERR_NOTDIR,
    390        1.25      fvdl 	NFSERR_NOSPC,
    391        1.25      fvdl 	NFSERR_ROFS,
    392        1.25      fvdl 	NFSERR_NAMETOL,
    393        1.25      fvdl 	NFSERR_DQUOT,
    394        1.25      fvdl 	NFSERR_STALE,
    395        1.25      fvdl 	NFSERR_BADHANDLE,
    396        1.25      fvdl 	NFSERR_NOTSUPP,
    397        1.25      fvdl 	NFSERR_SERVERFAULT,
    398        1.25      fvdl 	NFSERR_BADTYPE,
    399        1.25      fvdl 	0,
    400        1.25      fvdl };
    401        1.25      fvdl 
    402        1.90  jdolecek static const short nfsv3err_remove[] = {
    403        1.25      fvdl 	NFSERR_IO,
    404        1.25      fvdl 	NFSERR_NOENT,
    405        1.25      fvdl 	NFSERR_IO,
    406        1.25      fvdl 	NFSERR_ACCES,
    407        1.25      fvdl 	NFSERR_NOTDIR,
    408        1.25      fvdl 	NFSERR_ROFS,
    409        1.25      fvdl 	NFSERR_NAMETOL,
    410        1.25      fvdl 	NFSERR_STALE,
    411        1.25      fvdl 	NFSERR_BADHANDLE,
    412        1.25      fvdl 	NFSERR_SERVERFAULT,
    413        1.25      fvdl 	0,
    414        1.25      fvdl };
    415        1.25      fvdl 
    416        1.90  jdolecek static const short nfsv3err_rmdir[] = {
    417        1.25      fvdl 	NFSERR_IO,
    418        1.25      fvdl 	NFSERR_NOENT,
    419        1.25      fvdl 	NFSERR_IO,
    420        1.25      fvdl 	NFSERR_ACCES,
    421        1.25      fvdl 	NFSERR_EXIST,
    422        1.25      fvdl 	NFSERR_NOTDIR,
    423        1.25      fvdl 	NFSERR_INVAL,
    424        1.25      fvdl 	NFSERR_ROFS,
    425        1.25      fvdl 	NFSERR_NAMETOL,
    426        1.25      fvdl 	NFSERR_NOTEMPTY,
    427        1.25      fvdl 	NFSERR_STALE,
    428        1.25      fvdl 	NFSERR_BADHANDLE,
    429        1.25      fvdl 	NFSERR_NOTSUPP,
    430        1.25      fvdl 	NFSERR_SERVERFAULT,
    431        1.25      fvdl 	0,
    432        1.25      fvdl };
    433        1.25      fvdl 
    434        1.90  jdolecek static const short nfsv3err_rename[] = {
    435        1.25      fvdl 	NFSERR_IO,
    436        1.25      fvdl 	NFSERR_NOENT,
    437        1.25      fvdl 	NFSERR_IO,
    438        1.25      fvdl 	NFSERR_ACCES,
    439        1.25      fvdl 	NFSERR_EXIST,
    440        1.25      fvdl 	NFSERR_XDEV,
    441        1.25      fvdl 	NFSERR_NOTDIR,
    442        1.25      fvdl 	NFSERR_ISDIR,
    443        1.25      fvdl 	NFSERR_INVAL,
    444        1.25      fvdl 	NFSERR_NOSPC,
    445        1.25      fvdl 	NFSERR_ROFS,
    446        1.25      fvdl 	NFSERR_MLINK,
    447        1.25      fvdl 	NFSERR_NAMETOL,
    448        1.25      fvdl 	NFSERR_NOTEMPTY,
    449        1.25      fvdl 	NFSERR_DQUOT,
    450        1.25      fvdl 	NFSERR_STALE,
    451        1.25      fvdl 	NFSERR_BADHANDLE,
    452        1.25      fvdl 	NFSERR_NOTSUPP,
    453        1.25      fvdl 	NFSERR_SERVERFAULT,
    454        1.25      fvdl 	0,
    455        1.25      fvdl };
    456        1.25      fvdl 
    457        1.90  jdolecek static const short nfsv3err_link[] = {
    458        1.25      fvdl 	NFSERR_IO,
    459        1.25      fvdl 	NFSERR_IO,
    460        1.25      fvdl 	NFSERR_ACCES,
    461        1.25      fvdl 	NFSERR_EXIST,
    462        1.25      fvdl 	NFSERR_XDEV,
    463        1.25      fvdl 	NFSERR_NOTDIR,
    464        1.25      fvdl 	NFSERR_INVAL,
    465        1.25      fvdl 	NFSERR_NOSPC,
    466        1.25      fvdl 	NFSERR_ROFS,
    467        1.25      fvdl 	NFSERR_MLINK,
    468        1.25      fvdl 	NFSERR_NAMETOL,
    469        1.25      fvdl 	NFSERR_DQUOT,
    470        1.25      fvdl 	NFSERR_STALE,
    471        1.25      fvdl 	NFSERR_BADHANDLE,
    472        1.25      fvdl 	NFSERR_NOTSUPP,
    473        1.25      fvdl 	NFSERR_SERVERFAULT,
    474        1.25      fvdl 	0,
    475        1.25      fvdl };
    476        1.25      fvdl 
    477        1.90  jdolecek static const short nfsv3err_readdir[] = {
    478        1.25      fvdl 	NFSERR_IO,
    479        1.25      fvdl 	NFSERR_IO,
    480        1.25      fvdl 	NFSERR_ACCES,
    481        1.25      fvdl 	NFSERR_NOTDIR,
    482        1.25      fvdl 	NFSERR_STALE,
    483        1.25      fvdl 	NFSERR_BADHANDLE,
    484        1.25      fvdl 	NFSERR_BAD_COOKIE,
    485        1.25      fvdl 	NFSERR_TOOSMALL,
    486        1.25      fvdl 	NFSERR_SERVERFAULT,
    487        1.25      fvdl 	0,
    488        1.25      fvdl };
    489        1.25      fvdl 
    490        1.90  jdolecek static const short nfsv3err_readdirplus[] = {
    491        1.25      fvdl 	NFSERR_IO,
    492        1.25      fvdl 	NFSERR_IO,
    493        1.25      fvdl 	NFSERR_ACCES,
    494        1.25      fvdl 	NFSERR_NOTDIR,
    495        1.25      fvdl 	NFSERR_STALE,
    496        1.25      fvdl 	NFSERR_BADHANDLE,
    497        1.25      fvdl 	NFSERR_BAD_COOKIE,
    498        1.25      fvdl 	NFSERR_NOTSUPP,
    499        1.25      fvdl 	NFSERR_TOOSMALL,
    500        1.25      fvdl 	NFSERR_SERVERFAULT,
    501        1.25      fvdl 	0,
    502        1.25      fvdl };
    503        1.25      fvdl 
    504        1.90  jdolecek static const short nfsv3err_fsstat[] = {
    505        1.25      fvdl 	NFSERR_IO,
    506        1.25      fvdl 	NFSERR_IO,
    507        1.25      fvdl 	NFSERR_STALE,
    508        1.25      fvdl 	NFSERR_BADHANDLE,
    509        1.25      fvdl 	NFSERR_SERVERFAULT,
    510        1.25      fvdl 	0,
    511        1.25      fvdl };
    512        1.25      fvdl 
    513        1.90  jdolecek static const short nfsv3err_fsinfo[] = {
    514        1.25      fvdl 	NFSERR_STALE,
    515        1.25      fvdl 	NFSERR_STALE,
    516        1.25      fvdl 	NFSERR_BADHANDLE,
    517        1.25      fvdl 	NFSERR_SERVERFAULT,
    518        1.25      fvdl 	0,
    519        1.25      fvdl };
    520        1.25      fvdl 
    521        1.90  jdolecek static const short nfsv3err_pathconf[] = {
    522        1.25      fvdl 	NFSERR_STALE,
    523        1.25      fvdl 	NFSERR_STALE,
    524        1.25      fvdl 	NFSERR_BADHANDLE,
    525        1.25      fvdl 	NFSERR_SERVERFAULT,
    526        1.25      fvdl 	0,
    527        1.25      fvdl };
    528        1.25      fvdl 
    529        1.90  jdolecek static const short nfsv3err_commit[] = {
    530        1.25      fvdl 	NFSERR_IO,
    531        1.25      fvdl 	NFSERR_IO,
    532        1.25      fvdl 	NFSERR_STALE,
    533        1.25      fvdl 	NFSERR_BADHANDLE,
    534        1.25      fvdl 	NFSERR_SERVERFAULT,
    535        1.25      fvdl 	0,
    536        1.25      fvdl };
    537        1.25      fvdl 
    538        1.90  jdolecek static const short * const nfsrv_v3errmap[] = {
    539        1.25      fvdl 	nfsv3err_null,
    540        1.25      fvdl 	nfsv3err_getattr,
    541        1.25      fvdl 	nfsv3err_setattr,
    542        1.25      fvdl 	nfsv3err_lookup,
    543        1.25      fvdl 	nfsv3err_access,
    544        1.25      fvdl 	nfsv3err_readlink,
    545        1.25      fvdl 	nfsv3err_read,
    546        1.25      fvdl 	nfsv3err_write,
    547        1.25      fvdl 	nfsv3err_create,
    548        1.25      fvdl 	nfsv3err_mkdir,
    549        1.25      fvdl 	nfsv3err_symlink,
    550        1.25      fvdl 	nfsv3err_mknod,
    551        1.25      fvdl 	nfsv3err_remove,
    552        1.25      fvdl 	nfsv3err_rmdir,
    553        1.25      fvdl 	nfsv3err_rename,
    554        1.25      fvdl 	nfsv3err_link,
    555        1.25      fvdl 	nfsv3err_readdir,
    556        1.25      fvdl 	nfsv3err_readdirplus,
    557        1.25      fvdl 	nfsv3err_fsstat,
    558        1.25      fvdl 	nfsv3err_fsinfo,
    559        1.25      fvdl 	nfsv3err_pathconf,
    560        1.25      fvdl 	nfsv3err_commit,
    561        1.25      fvdl };
    562        1.25      fvdl 
    563        1.12   mycroft extern struct nfsrtt nfsrtt;
    564         1.1       cgd 
    565        1.46      fvdl u_long nfsdirhashmask;
    566        1.18   mycroft 
    567       1.213       dsl int nfs_webnamei(struct nameidata *, struct vnode *, struct proc *);
    568        1.43      fvdl 
    569         1.1       cgd /*
    570         1.1       cgd  * Create the header for an rpc request packet
    571         1.1       cgd  * The hsiz is the size of the rest of the nfs request header.
    572         1.1       cgd  * (just used to decide if a cluster is a good idea)
    573         1.1       cgd  */
    574        1.12   mycroft struct mbuf *
    575       1.183  christos nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
    576        1.12   mycroft {
    577        1.75  augustss 	struct mbuf *mb;
    578       1.183  christos 	char *bpos;
    579        1.12   mycroft 
    580       1.109      matt 	mb = m_get(M_WAIT, MT_DATA);
    581       1.109      matt 	MCLAIM(mb, &nfs_mowner);
    582        1.12   mycroft 	if (hsiz >= MINCLSIZE)
    583       1.109      matt 		m_clget(mb, M_WAIT);
    584        1.12   mycroft 	mb->m_len = 0;
    585       1.183  christos 	bpos = mtod(mb, void *);
    586       1.148     perry 
    587        1.12   mycroft 	/* Finally, return values */
    588        1.12   mycroft 	*bposp = bpos;
    589        1.12   mycroft 	return (mb);
    590        1.12   mycroft }
    591        1.12   mycroft 
    592        1.12   mycroft /*
    593        1.12   mycroft  * Build the RPC header and fill in the authorization info.
    594        1.12   mycroft  * The authorization string argument is only used when the credentials
    595        1.12   mycroft  * come from outside of the kernel.
    596        1.12   mycroft  * Returns the head of the mbuf list.
    597        1.12   mycroft  */
    598        1.12   mycroft struct mbuf *
    599       1.216    cegger nfsm_rpchead(kauth_cred_t cr, int nmflag, int procid,
    600       1.216    cegger 	int auth_type, int auth_len, char *auth_str, int verf_len,
    601       1.216    cegger 	char *verf_str, struct mbuf *mrest, int mrest_len,
    602       1.216    cegger 	struct mbuf **mbp, uint32_t *xidp)
    603         1.1       cgd {
    604        1.75  augustss 	struct mbuf *mb;
    605        1.75  augustss 	u_int32_t *tl;
    606       1.183  christos 	char *bpos;
    607        1.75  augustss 	int i;
    608       1.109      matt 	struct mbuf *mreq;
    609        1.12   mycroft 	int siz, grpsiz, authsiz;
    610         1.1       cgd 
    611        1.12   mycroft 	authsiz = nfsm_rndup(auth_len);
    612       1.109      matt 	mb = m_gethdr(M_WAIT, MT_DATA);
    613       1.109      matt 	MCLAIM(mb, &nfs_mowner);
    614        1.25      fvdl 	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
    615       1.109      matt 		m_clget(mb, M_WAIT);
    616        1.25      fvdl 	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
    617        1.25      fvdl 		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
    618        1.12   mycroft 	} else {
    619        1.25      fvdl 		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
    620         1.1       cgd 	}
    621        1.12   mycroft 	mb->m_len = 0;
    622        1.12   mycroft 	mreq = mb;
    623       1.183  christos 	bpos = mtod(mb, void *);
    624        1.12   mycroft 
    625        1.12   mycroft 	/*
    626        1.12   mycroft 	 * First the RPC header.
    627        1.12   mycroft 	 */
    628        1.25      fvdl 	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
    629        1.30      fvdl 
    630       1.126      yamt 	*tl++ = *xidp = nfs_getxid();
    631         1.1       cgd 	*tl++ = rpc_call;
    632         1.1       cgd 	*tl++ = rpc_vers;
    633       1.179      yamt 	*tl++ = txdr_unsigned(NFS_PROG);
    634       1.179      yamt 	if (nmflag & NFSMNT_NFSV3)
    635       1.179      yamt 		*tl++ = txdr_unsigned(NFS_VER3);
    636       1.179      yamt 	else
    637       1.179      yamt 		*tl++ = txdr_unsigned(NFS_VER2);
    638        1.25      fvdl 	if (nmflag & NFSMNT_NFSV3)
    639        1.25      fvdl 		*tl++ = txdr_unsigned(procid);
    640        1.25      fvdl 	else
    641        1.25      fvdl 		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
    642        1.12   mycroft 
    643        1.12   mycroft 	/*
    644        1.12   mycroft 	 * And then the authorization cred.
    645        1.12   mycroft 	 */
    646        1.12   mycroft 	*tl++ = txdr_unsigned(auth_type);
    647        1.12   mycroft 	*tl = txdr_unsigned(authsiz);
    648        1.12   mycroft 	switch (auth_type) {
    649        1.12   mycroft 	case RPCAUTH_UNIX:
    650        1.22       cgd 		nfsm_build(tl, u_int32_t *, auth_len);
    651        1.12   mycroft 		*tl++ = 0;		/* stamp ?? */
    652        1.12   mycroft 		*tl++ = 0;		/* NULL hostname */
    653       1.162      elad 		*tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
    654       1.162      elad 		*tl++ = txdr_unsigned(kauth_cred_getegid(cr));
    655        1.12   mycroft 		grpsiz = (auth_len >> 2) - 5;
    656        1.12   mycroft 		*tl++ = txdr_unsigned(grpsiz);
    657        1.20   mycroft 		for (i = 0; i < grpsiz; i++)
    658       1.162      elad 			*tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
    659        1.12   mycroft 		break;
    660        1.25      fvdl 	case RPCAUTH_KERB4:
    661        1.12   mycroft 		siz = auth_len;
    662        1.12   mycroft 		while (siz > 0) {
    663        1.12   mycroft 			if (M_TRAILINGSPACE(mb) == 0) {
    664       1.109      matt 				struct mbuf *mb2;
    665       1.109      matt 				mb2 = m_get(M_WAIT, MT_DATA);
    666       1.109      matt 				MCLAIM(mb2, &nfs_mowner);
    667        1.12   mycroft 				if (siz >= MINCLSIZE)
    668       1.109      matt 					m_clget(mb2, M_WAIT);
    669        1.12   mycroft 				mb->m_next = mb2;
    670        1.12   mycroft 				mb = mb2;
    671        1.12   mycroft 				mb->m_len = 0;
    672       1.183  christos 				bpos = mtod(mb, void *);
    673        1.12   mycroft 			}
    674        1.12   mycroft 			i = min(siz, M_TRAILINGSPACE(mb));
    675        1.63     perry 			memcpy(bpos, auth_str, i);
    676        1.12   mycroft 			mb->m_len += i;
    677        1.12   mycroft 			auth_str += i;
    678        1.12   mycroft 			bpos += i;
    679        1.12   mycroft 			siz -= i;
    680        1.12   mycroft 		}
    681        1.12   mycroft 		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
    682        1.12   mycroft 			for (i = 0; i < siz; i++)
    683        1.12   mycroft 				*bpos++ = '\0';
    684        1.12   mycroft 			mb->m_len += siz;
    685        1.12   mycroft 		}
    686        1.12   mycroft 		break;
    687        1.12   mycroft 	};
    688        1.25      fvdl 
    689        1.25      fvdl 	/*
    690        1.25      fvdl 	 * And the verifier...
    691        1.25      fvdl 	 */
    692        1.25      fvdl 	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    693        1.25      fvdl 	if (verf_str) {
    694        1.25      fvdl 		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
    695        1.25      fvdl 		*tl = txdr_unsigned(verf_len);
    696        1.25      fvdl 		siz = verf_len;
    697        1.25      fvdl 		while (siz > 0) {
    698        1.25      fvdl 			if (M_TRAILINGSPACE(mb) == 0) {
    699       1.109      matt 				struct mbuf *mb2;
    700       1.109      matt 				mb2 = m_get(M_WAIT, MT_DATA);
    701       1.109      matt 				MCLAIM(mb2, &nfs_mowner);
    702        1.25      fvdl 				if (siz >= MINCLSIZE)
    703       1.109      matt 					m_clget(mb2, M_WAIT);
    704        1.25      fvdl 				mb->m_next = mb2;
    705        1.25      fvdl 				mb = mb2;
    706        1.25      fvdl 				mb->m_len = 0;
    707       1.183  christos 				bpos = mtod(mb, void *);
    708        1.25      fvdl 			}
    709        1.25      fvdl 			i = min(siz, M_TRAILINGSPACE(mb));
    710        1.63     perry 			memcpy(bpos, verf_str, i);
    711        1.25      fvdl 			mb->m_len += i;
    712        1.25      fvdl 			verf_str += i;
    713        1.25      fvdl 			bpos += i;
    714        1.25      fvdl 			siz -= i;
    715        1.25      fvdl 		}
    716        1.25      fvdl 		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
    717        1.25      fvdl 			for (i = 0; i < siz; i++)
    718        1.25      fvdl 				*bpos++ = '\0';
    719        1.25      fvdl 			mb->m_len += siz;
    720        1.25      fvdl 		}
    721        1.25      fvdl 	} else {
    722        1.25      fvdl 		*tl++ = txdr_unsigned(RPCAUTH_NULL);
    723        1.25      fvdl 		*tl = 0;
    724        1.25      fvdl 	}
    725        1.12   mycroft 	mb->m_next = mrest;
    726        1.25      fvdl 	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
    727        1.12   mycroft 	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
    728        1.12   mycroft 	*mbp = mb;
    729         1.1       cgd 	return (mreq);
    730         1.1       cgd }
    731         1.1       cgd 
    732         1.1       cgd /*
    733         1.1       cgd  * copies mbuf chain to the uio scatter/gather list
    734         1.1       cgd  */
    735        1.24  christos int
    736       1.214       dsl nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, char **dpos)
    737         1.1       cgd {
    738        1.75  augustss 	char *mbufcp, *uiocp;
    739        1.75  augustss 	int xfer, left, len;
    740        1.75  augustss 	struct mbuf *mp;
    741         1.1       cgd 	long uiosiz, rem;
    742         1.1       cgd 	int error = 0;
    743         1.1       cgd 
    744         1.1       cgd 	mp = *mrep;
    745         1.1       cgd 	mbufcp = *dpos;
    746       1.183  christos 	len = mtod(mp, char *) + mp->m_len - mbufcp;
    747         1.1       cgd 	rem = nfsm_rndup(siz)-siz;
    748         1.1       cgd 	while (siz > 0) {
    749         1.1       cgd 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
    750         1.1       cgd 			return (EFBIG);
    751         1.1       cgd 		left = uiop->uio_iov->iov_len;
    752         1.1       cgd 		uiocp = uiop->uio_iov->iov_base;
    753         1.1       cgd 		if (left > siz)
    754         1.1       cgd 			left = siz;
    755         1.1       cgd 		uiosiz = left;
    756         1.1       cgd 		while (left > 0) {
    757         1.1       cgd 			while (len == 0) {
    758         1.1       cgd 				mp = mp->m_next;
    759         1.1       cgd 				if (mp == NULL)
    760         1.1       cgd 					return (EBADRPC);
    761       1.183  christos 				mbufcp = mtod(mp, void *);
    762         1.1       cgd 				len = mp->m_len;
    763         1.1       cgd 			}
    764         1.1       cgd 			xfer = (left > len) ? len : left;
    765       1.158      yamt 			error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
    766       1.158      yamt 			    uiocp, xfer);
    767       1.158      yamt 			if (error) {
    768       1.158      yamt 				return error;
    769       1.158      yamt 			}
    770         1.1       cgd 			left -= xfer;
    771         1.1       cgd 			len -= xfer;
    772         1.1       cgd 			mbufcp += xfer;
    773         1.1       cgd 			uiocp += xfer;
    774         1.1       cgd 			uiop->uio_offset += xfer;
    775         1.1       cgd 			uiop->uio_resid -= xfer;
    776         1.1       cgd 		}
    777         1.1       cgd 		if (uiop->uio_iov->iov_len <= siz) {
    778         1.1       cgd 			uiop->uio_iovcnt--;
    779         1.1       cgd 			uiop->uio_iov++;
    780         1.1       cgd 		} else {
    781        1.95     lukem 			uiop->uio_iov->iov_base =
    782       1.183  christos 			    (char *)uiop->uio_iov->iov_base + uiosiz;
    783         1.1       cgd 			uiop->uio_iov->iov_len -= uiosiz;
    784         1.1       cgd 		}
    785         1.1       cgd 		siz -= uiosiz;
    786         1.1       cgd 	}
    787         1.1       cgd 	*dpos = mbufcp;
    788         1.1       cgd 	*mrep = mp;
    789         1.1       cgd 	if (rem > 0) {
    790         1.1       cgd 		if (len < rem)
    791         1.1       cgd 			error = nfs_adv(mrep, dpos, rem, len);
    792         1.1       cgd 		else
    793         1.1       cgd 			*dpos += rem;
    794         1.1       cgd 	}
    795         1.1       cgd 	return (error);
    796         1.1       cgd }
    797         1.1       cgd 
    798         1.1       cgd /*
    799        1.29      fvdl  * copies a uio scatter/gather list to an mbuf chain.
    800        1.29      fvdl  * NOTE: can ony handle iovcnt == 1
    801         1.1       cgd  */
    802        1.24  christos int
    803       1.214       dsl nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, char **bpos)
    804         1.1       cgd {
    805        1.75  augustss 	char *uiocp;
    806        1.75  augustss 	struct mbuf *mp, *mp2;
    807        1.75  augustss 	int xfer, left, mlen;
    808         1.1       cgd 	int uiosiz, clflg, rem;
    809         1.1       cgd 	char *cp;
    810       1.158      yamt 	int error;
    811         1.1       cgd 
    812        1.29      fvdl #ifdef DIAGNOSTIC
    813        1.29      fvdl 	if (uiop->uio_iovcnt != 1)
    814        1.29      fvdl 		panic("nfsm_uiotombuf: iovcnt != 1");
    815        1.29      fvdl #endif
    816        1.29      fvdl 
    817         1.1       cgd 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
    818         1.1       cgd 		clflg = 1;
    819         1.1       cgd 	else
    820         1.1       cgd 		clflg = 0;
    821         1.1       cgd 	rem = nfsm_rndup(siz)-siz;
    822        1.12   mycroft 	mp = mp2 = *mq;
    823         1.1       cgd 	while (siz > 0) {
    824         1.1       cgd 		left = uiop->uio_iov->iov_len;
    825         1.1       cgd 		uiocp = uiop->uio_iov->iov_base;
    826         1.1       cgd 		if (left > siz)
    827         1.1       cgd 			left = siz;
    828         1.1       cgd 		uiosiz = left;
    829         1.1       cgd 		while (left > 0) {
    830        1.12   mycroft 			mlen = M_TRAILINGSPACE(mp);
    831        1.12   mycroft 			if (mlen == 0) {
    832       1.109      matt 				mp = m_get(M_WAIT, MT_DATA);
    833       1.109      matt 				MCLAIM(mp, &nfs_mowner);
    834        1.12   mycroft 				if (clflg)
    835       1.109      matt 					m_clget(mp, M_WAIT);
    836        1.12   mycroft 				mp->m_len = 0;
    837        1.12   mycroft 				mp2->m_next = mp;
    838        1.12   mycroft 				mp2 = mp;
    839        1.12   mycroft 				mlen = M_TRAILINGSPACE(mp);
    840        1.12   mycroft 			}
    841        1.12   mycroft 			xfer = (left > mlen) ? mlen : left;
    842       1.183  christos 			cp = mtod(mp, char *) + mp->m_len;
    843       1.158      yamt 			error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
    844       1.158      yamt 			    xfer);
    845       1.158      yamt 			if (error) {
    846       1.158      yamt 				/* XXX */
    847       1.158      yamt 			}
    848        1.12   mycroft 			mp->m_len += xfer;
    849         1.1       cgd 			left -= xfer;
    850         1.1       cgd 			uiocp += xfer;
    851         1.1       cgd 			uiop->uio_offset += xfer;
    852         1.1       cgd 			uiop->uio_resid -= xfer;
    853         1.1       cgd 		}
    854       1.183  christos 		uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
    855        1.95     lukem 		    uiosiz;
    856        1.29      fvdl 		uiop->uio_iov->iov_len -= uiosiz;
    857         1.1       cgd 		siz -= uiosiz;
    858         1.1       cgd 	}
    859         1.1       cgd 	if (rem > 0) {
    860        1.12   mycroft 		if (rem > M_TRAILINGSPACE(mp)) {
    861       1.109      matt 			mp = m_get(M_WAIT, MT_DATA);
    862       1.109      matt 			MCLAIM(mp, &nfs_mowner);
    863         1.1       cgd 			mp->m_len = 0;
    864         1.1       cgd 			mp2->m_next = mp;
    865         1.1       cgd 		}
    866       1.183  christos 		cp = mtod(mp, char *) + mp->m_len;
    867         1.1       cgd 		for (left = 0; left < rem; left++)
    868         1.1       cgd 			*cp++ = '\0';
    869         1.1       cgd 		mp->m_len += rem;
    870         1.1       cgd 		*bpos = cp;
    871         1.1       cgd 	} else
    872       1.183  christos 		*bpos = mtod(mp, char *) + mp->m_len;
    873         1.1       cgd 	*mq = mp;
    874         1.1       cgd 	return (0);
    875         1.1       cgd }
    876         1.1       cgd 
    877         1.1       cgd /*
    878        1.39      fvdl  * Get at least "siz" bytes of correctly aligned data.
    879        1.39      fvdl  * When called the mbuf pointers are not necessarily correct,
    880        1.39      fvdl  * dsosp points to what ought to be in m_data and left contains
    881       1.148     perry  * what ought to be in m_len.
    882        1.12   mycroft  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
    883         1.1       cgd  * cases. (The macros use the vars. dpos and dpos2)
    884         1.1       cgd  */
    885        1.24  christos int
    886       1.214       dsl nfsm_disct(struct mbuf **mdp, char **dposp, int siz, int left, char **cp2)
    887         1.1       cgd {
    888        1.75  augustss 	struct mbuf *m1, *m2;
    889        1.39      fvdl 	struct mbuf *havebuf = NULL;
    890       1.183  christos 	char *src = *dposp;
    891       1.183  christos 	char *dst;
    892        1.39      fvdl 	int len;
    893        1.39      fvdl 
    894        1.39      fvdl #ifdef DEBUG
    895        1.39      fvdl 	if (left < 0)
    896       1.148     perry 		panic("nfsm_disct: left < 0");
    897        1.39      fvdl #endif
    898        1.39      fvdl 	m1 = *mdp;
    899        1.39      fvdl 	/*
    900        1.39      fvdl 	 * Skip through the mbuf chain looking for an mbuf with
    901        1.39      fvdl 	 * some data. If the first mbuf found has enough data
    902        1.39      fvdl 	 * and it is correctly aligned return it.
    903        1.39      fvdl 	 */
    904         1.1       cgd 	while (left == 0) {
    905        1.39      fvdl 		havebuf = m1;
    906        1.39      fvdl 		*mdp = m1 = m1->m_next;
    907        1.39      fvdl 		if (m1 == NULL)
    908         1.1       cgd 			return (EBADRPC);
    909       1.183  christos 		src = mtod(m1, void *);
    910        1.39      fvdl 		left = m1->m_len;
    911        1.39      fvdl 		/*
    912        1.39      fvdl 		 * If we start a new mbuf and it is big enough
    913        1.39      fvdl 		 * and correctly aligned just return it, don't
    914        1.39      fvdl 		 * do any pull up.
    915        1.39      fvdl 		 */
    916        1.39      fvdl 		if (left >= siz && nfsm_aligned(src)) {
    917        1.39      fvdl 			*cp2 = src;
    918        1.39      fvdl 			*dposp = src + siz;
    919        1.39      fvdl 			return (0);
    920        1.39      fvdl 		}
    921         1.1       cgd 	}
    922       1.201      yamt 	if ((m1->m_flags & M_EXT) != 0) {
    923       1.201      yamt 		if (havebuf && M_TRAILINGSPACE(havebuf) >= siz &&
    924       1.201      yamt 		    nfsm_aligned(mtod(havebuf, char *) + havebuf->m_len)) {
    925       1.201      yamt 			/*
    926       1.201      yamt 			 * If the first mbuf with data has external data
    927       1.201      yamt 			 * and there is a previous mbuf with some trailing
    928       1.201      yamt 			 * space, use it to move the data into.
    929        1.39      fvdl 			 */
    930        1.39      fvdl 			m2 = m1;
    931        1.39      fvdl 			*mdp = m1 = havebuf;
    932       1.201      yamt 			*cp2 = mtod(m1, char *) + m1->m_len;
    933       1.201      yamt 		} else if (havebuf) {
    934        1.39      fvdl 			/*
    935        1.39      fvdl 			 * If the first mbuf has a external data
    936        1.39      fvdl 			 * and there is no previous empty mbuf
    937        1.39      fvdl 			 * allocate a new mbuf and move the external
    938       1.148     perry 			 * data to the new mbuf. Also make the first
    939        1.39      fvdl 			 * mbuf look empty.
    940        1.39      fvdl 			 */
    941       1.201      yamt 			m2 = m1;
    942       1.201      yamt 			*mdp = m1 = m_get(M_WAIT, MT_DATA);
    943       1.201      yamt 			MCLAIM(m1, m2->m_owner);
    944       1.201      yamt 			if ((m2->m_flags & M_PKTHDR) != 0) {
    945       1.201      yamt 				/* XXX MOVE */
    946       1.201      yamt 				M_COPY_PKTHDR(m1, m2);
    947       1.201      yamt 				m_tag_delete_chain(m2, NULL);
    948       1.201      yamt 				m2->m_flags &= ~M_PKTHDR;
    949       1.201      yamt 			}
    950       1.201      yamt 			if (havebuf) {
    951       1.201      yamt 				havebuf->m_next = m1;
    952       1.201      yamt 			}
    953       1.201      yamt 			m1->m_next = m2;
    954       1.201      yamt 			MRESETDATA(m1);
    955       1.201      yamt 			m1->m_len = 0;
    956        1.39      fvdl 			m2->m_data = src;
    957        1.39      fvdl 			m2->m_len = left;
    958       1.201      yamt 			*cp2 = mtod(m1, char *);
    959       1.201      yamt 		} else {
    960       1.201      yamt 			struct mbuf **nextp = &m1->m_next;
    961       1.201      yamt 
    962       1.201      yamt 			m1->m_len -= left;
    963       1.201      yamt 			do {
    964       1.201      yamt 				m2 = m_get(M_WAIT, MT_DATA);
    965       1.201      yamt 				MCLAIM(m2, m1->m_owner);
    966       1.201      yamt 				if (left >= MINCLSIZE) {
    967       1.201      yamt 					MCLGET(m2, M_WAIT);
    968       1.201      yamt 				}
    969       1.201      yamt 				m2->m_next = *nextp;
    970       1.201      yamt 				*nextp = m2;
    971       1.201      yamt 				nextp = &m2->m_next;
    972       1.201      yamt 				len = (m2->m_flags & M_EXT) != 0 ?
    973       1.201      yamt 				    MCLBYTES : MLEN;
    974       1.201      yamt 				if (len > left) {
    975       1.201      yamt 					len = left;
    976       1.201      yamt 				}
    977       1.201      yamt 				memcpy(mtod(m2, char *), src, len);
    978       1.201      yamt 				m2->m_len = len;
    979       1.201      yamt 				src += len;
    980       1.201      yamt 				left -= len;
    981       1.201      yamt 			} while (left > 0);
    982       1.201      yamt 			*mdp = m1 = m1->m_next;
    983       1.201      yamt 			m2 = m1->m_next;
    984       1.201      yamt 			*cp2 = mtod(m1, char *);
    985         1.1       cgd 		}
    986        1.39      fvdl 	} else {
    987        1.39      fvdl 		/*
    988        1.39      fvdl 		 * If the first mbuf has no external data
    989        1.39      fvdl 		 * move the data to the front of the mbuf.
    990        1.39      fvdl 		 */
    991       1.201      yamt 		MRESETDATA(m1);
    992       1.201      yamt 		dst = mtod(m1, char *);
    993       1.201      yamt 		if (dst != src) {
    994        1.63     perry 			memmove(dst, src, left);
    995       1.201      yamt 		}
    996        1.39      fvdl 		m1->m_len = left;
    997        1.39      fvdl 		m2 = m1->m_next;
    998       1.201      yamt 		*cp2 = m1->m_data;
    999         1.1       cgd 	}
   1000       1.201      yamt 	*dposp = *cp2 + siz;
   1001        1.39      fvdl 	/*
   1002        1.39      fvdl 	 * Loop through mbufs pulling data up into first mbuf until
   1003        1.39      fvdl 	 * the first mbuf is full or there is no more data to
   1004        1.39      fvdl 	 * pullup.
   1005        1.39      fvdl 	 */
   1006       1.201      yamt 	dst = mtod(m1, char *) + m1->m_len;
   1007       1.129    itojun 	while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
   1008       1.201      yamt 		if ((len = min(len, m2->m_len)) != 0) {
   1009       1.201      yamt 			memcpy(dst, mtod(m2, char *), len);
   1010       1.201      yamt 		}
   1011        1.39      fvdl 		m1->m_len += len;
   1012        1.39      fvdl 		dst += len;
   1013        1.39      fvdl 		m2->m_data += len;
   1014        1.39      fvdl 		m2->m_len -= len;
   1015        1.39      fvdl 		m2 = m2->m_next;
   1016        1.39      fvdl 	}
   1017        1.39      fvdl 	if (m1->m_len < siz)
   1018        1.39      fvdl 		return (EBADRPC);
   1019         1.1       cgd 	return (0);
   1020         1.1       cgd }
   1021         1.1       cgd 
   1022         1.1       cgd /*
   1023         1.1       cgd  * Advance the position in the mbuf chain.
   1024         1.1       cgd  */
   1025        1.24  christos int
   1026       1.214       dsl nfs_adv(struct mbuf **mdp, char **dposp, int offs, int left)
   1027         1.1       cgd {
   1028        1.75  augustss 	struct mbuf *m;
   1029        1.75  augustss 	int s;
   1030         1.1       cgd 
   1031         1.1       cgd 	m = *mdp;
   1032         1.1       cgd 	s = left;
   1033         1.1       cgd 	while (s < offs) {
   1034         1.1       cgd 		offs -= s;
   1035         1.1       cgd 		m = m->m_next;
   1036         1.1       cgd 		if (m == NULL)
   1037         1.1       cgd 			return (EBADRPC);
   1038         1.1       cgd 		s = m->m_len;
   1039         1.1       cgd 	}
   1040         1.1       cgd 	*mdp = m;
   1041       1.183  christos 	*dposp = mtod(m, char *) + offs;
   1042         1.1       cgd 	return (0);
   1043         1.1       cgd }
   1044         1.1       cgd 
   1045         1.1       cgd /*
   1046         1.1       cgd  * Copy a string into mbufs for the hard cases...
   1047         1.1       cgd  */
   1048        1.24  christos int
   1049       1.214       dsl nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
   1050         1.1       cgd {
   1051        1.75  augustss 	struct mbuf *m1 = NULL, *m2;
   1052         1.1       cgd 	long left, xfer, len, tlen;
   1053        1.22       cgd 	u_int32_t *tl;
   1054         1.1       cgd 	int putsize;
   1055         1.1       cgd 
   1056         1.1       cgd 	putsize = 1;
   1057         1.1       cgd 	m2 = *mb;
   1058        1.12   mycroft 	left = M_TRAILINGSPACE(m2);
   1059         1.1       cgd 	if (left > 0) {
   1060        1.22       cgd 		tl = ((u_int32_t *)(*bpos));
   1061         1.1       cgd 		*tl++ = txdr_unsigned(siz);
   1062         1.1       cgd 		putsize = 0;
   1063         1.1       cgd 		left -= NFSX_UNSIGNED;
   1064         1.1       cgd 		m2->m_len += NFSX_UNSIGNED;
   1065         1.1       cgd 		if (left > 0) {
   1066       1.183  christos 			memcpy((void *) tl, cp, left);
   1067         1.1       cgd 			siz -= left;
   1068         1.1       cgd 			cp += left;
   1069         1.1       cgd 			m2->m_len += left;
   1070         1.1       cgd 			left = 0;
   1071         1.1       cgd 		}
   1072         1.1       cgd 	}
   1073        1.12   mycroft 	/* Loop around adding mbufs */
   1074         1.1       cgd 	while (siz > 0) {
   1075       1.109      matt 		m1 = m_get(M_WAIT, MT_DATA);
   1076       1.109      matt 		MCLAIM(m1, &nfs_mowner);
   1077         1.1       cgd 		if (siz > MLEN)
   1078       1.109      matt 			m_clget(m1, M_WAIT);
   1079         1.1       cgd 		m1->m_len = NFSMSIZ(m1);
   1080         1.1       cgd 		m2->m_next = m1;
   1081         1.1       cgd 		m2 = m1;
   1082        1.22       cgd 		tl = mtod(m1, u_int32_t *);
   1083         1.1       cgd 		tlen = 0;
   1084         1.1       cgd 		if (putsize) {
   1085         1.1       cgd 			*tl++ = txdr_unsigned(siz);
   1086         1.1       cgd 			m1->m_len -= NFSX_UNSIGNED;
   1087         1.1       cgd 			tlen = NFSX_UNSIGNED;
   1088         1.1       cgd 			putsize = 0;
   1089         1.1       cgd 		}
   1090         1.1       cgd 		if (siz < m1->m_len) {
   1091         1.1       cgd 			len = nfsm_rndup(siz);
   1092         1.1       cgd 			xfer = siz;
   1093         1.1       cgd 			if (xfer < len)
   1094         1.1       cgd 				*(tl+(xfer>>2)) = 0;
   1095         1.1       cgd 		} else {
   1096         1.1       cgd 			xfer = len = m1->m_len;
   1097         1.1       cgd 		}
   1098       1.183  christos 		memcpy((void *) tl, cp, xfer);
   1099         1.1       cgd 		m1->m_len = len+tlen;
   1100         1.1       cgd 		siz -= xfer;
   1101         1.1       cgd 		cp += xfer;
   1102         1.1       cgd 	}
   1103         1.1       cgd 	*mb = m1;
   1104       1.183  christos 	*bpos = mtod(m1, char *) + m1->m_len;
   1105         1.1       cgd 	return (0);
   1106         1.1       cgd }
   1107         1.1       cgd 
   1108        1.49      fvdl /*
   1109        1.49      fvdl  * Directory caching routines. They work as follows:
   1110        1.49      fvdl  * - a cache is maintained per VDIR nfsnode.
   1111        1.49      fvdl  * - for each offset cookie that is exported to userspace, and can
   1112        1.49      fvdl  *   thus be thrown back at us as an offset to VOP_READDIR, store
   1113        1.49      fvdl  *   information in the cache.
   1114        1.49      fvdl  * - cached are:
   1115        1.49      fvdl  *   - cookie itself
   1116        1.49      fvdl  *   - blocknumber (essentially just a search key in the buffer cache)
   1117        1.49      fvdl  *   - entry number in block.
   1118        1.49      fvdl  *   - offset cookie of block in which this entry is stored
   1119        1.49      fvdl  *   - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
   1120        1.49      fvdl  * - entries are looked up in a hash table
   1121        1.49      fvdl  * - also maintained is an LRU list of entries, used to determine
   1122        1.49      fvdl  *   which ones to delete if the cache grows too large.
   1123        1.49      fvdl  * - if 32 <-> 64 translation mode is requested for a filesystem,
   1124        1.49      fvdl  *   the cache also functions as a translation table
   1125        1.49      fvdl  * - in the translation case, invalidating the cache does not mean
   1126        1.49      fvdl  *   flushing it, but just marking entries as invalid, except for
   1127        1.49      fvdl  *   the <64bit cookie, 32bitcookie> pair which is still valid, to
   1128        1.49      fvdl  *   still be able to use the cache as a translation table.
   1129        1.49      fvdl  * - 32 bit cookies are uniquely created by combining the hash table
   1130        1.49      fvdl  *   entry value, and one generation count per hash table entry,
   1131        1.49      fvdl  *   incremented each time an entry is appended to the chain.
   1132        1.49      fvdl  * - the cache is invalidated each time a direcory is modified
   1133        1.49      fvdl  * - sanity checks are also done; if an entry in a block turns
   1134        1.49      fvdl  *   out not to have a matching cookie, the cache is invalidated
   1135        1.49      fvdl  *   and a new block starting from the wanted offset is fetched from
   1136        1.49      fvdl  *   the server.
   1137        1.49      fvdl  * - directory entries as read from the server are extended to contain
   1138        1.49      fvdl  *   the 64bit and, optionally, the 32bit cookies, for sanity checking
   1139        1.49      fvdl  *   the cache and exporting them to userspace through the cookie
   1140        1.49      fvdl  *   argument to VOP_READDIR.
   1141        1.49      fvdl  */
   1142        1.49      fvdl 
   1143        1.46      fvdl u_long
   1144       1.214       dsl nfs_dirhash(off_t off)
   1145        1.46      fvdl {
   1146        1.46      fvdl 	int i;
   1147        1.46      fvdl 	char *cp = (char *)&off;
   1148        1.46      fvdl 	u_long sum = 0L;
   1149        1.46      fvdl 
   1150        1.46      fvdl 	for (i = 0 ; i < sizeof (off); i++)
   1151        1.46      fvdl 		sum += *cp++;
   1152        1.46      fvdl 
   1153        1.46      fvdl 	return sum;
   1154        1.46      fvdl }
   1155        1.46      fvdl 
   1156       1.221     rmind #define	_NFSDC_MTX(np)		(NFSTOV(np)->v_interlock)
   1157       1.195        ad #define	NFSDC_LOCK(np)		mutex_enter(_NFSDC_MTX(np))
   1158       1.195        ad #define	NFSDC_UNLOCK(np)	mutex_exit(_NFSDC_MTX(np))
   1159       1.195        ad #define	NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
   1160       1.135      yamt 
   1161        1.49      fvdl void
   1162       1.214       dsl nfs_initdircache(struct vnode *vp)
   1163        1.49      fvdl {
   1164        1.49      fvdl 	struct nfsnode *np = VTONFS(vp);
   1165       1.135      yamt 	struct nfsdirhashhead *dircache;
   1166       1.120      yamt 
   1167       1.202        ad 	dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, true,
   1168       1.202        ad 	    &nfsdirhashmask);
   1169        1.49      fvdl 
   1170       1.135      yamt 	NFSDC_LOCK(np);
   1171       1.135      yamt 	if (np->n_dircache == NULL) {
   1172       1.135      yamt 		np->n_dircachesize = 0;
   1173       1.135      yamt 		np->n_dircache = dircache;
   1174       1.135      yamt 		dircache = NULL;
   1175       1.135      yamt 		TAILQ_INIT(&np->n_dirchain);
   1176       1.135      yamt 	}
   1177       1.135      yamt 	NFSDC_UNLOCK(np);
   1178       1.135      yamt 	if (dircache)
   1179       1.202        ad 		hashdone(dircache, HASH_LIST, nfsdirhashmask);
   1180       1.120      yamt }
   1181       1.120      yamt 
   1182       1.120      yamt void
   1183       1.214       dsl nfs_initdirxlatecookie(struct vnode *vp)
   1184       1.120      yamt {
   1185       1.120      yamt 	struct nfsnode *np = VTONFS(vp);
   1186       1.135      yamt 	unsigned *dirgens;
   1187       1.120      yamt 
   1188       1.120      yamt 	KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
   1189       1.120      yamt 
   1190       1.196      yamt 	dirgens = kmem_zalloc(NFS_DIRHASHSIZ * sizeof(unsigned), KM_SLEEP);
   1191       1.135      yamt 	NFSDC_LOCK(np);
   1192       1.135      yamt 	if (np->n_dirgens == NULL) {
   1193       1.135      yamt 		np->n_dirgens = dirgens;
   1194       1.135      yamt 		dirgens = NULL;
   1195       1.135      yamt 	}
   1196       1.135      yamt 	NFSDC_UNLOCK(np);
   1197       1.135      yamt 	if (dirgens)
   1198       1.196      yamt 		kmem_free(dirgens, NFS_DIRHASHSIZ * sizeof(unsigned));
   1199       1.135      yamt }
   1200       1.135      yamt 
   1201       1.135      yamt static const struct nfsdircache dzero;
   1202       1.135      yamt 
   1203       1.213       dsl static void nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *);
   1204       1.213       dsl static void nfs_putdircache_unlocked(struct nfsnode *,
   1205       1.213       dsl     struct nfsdircache *);
   1206       1.135      yamt 
   1207       1.135      yamt static void
   1208       1.214       dsl nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *ndp)
   1209       1.135      yamt {
   1210       1.135      yamt 
   1211       1.135      yamt 	NFSDC_ASSERT_LOCKED(np);
   1212       1.135      yamt 	KASSERT(ndp != &dzero);
   1213       1.135      yamt 
   1214       1.135      yamt 	if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
   1215       1.135      yamt 		return;
   1216       1.135      yamt 
   1217       1.135      yamt 	TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
   1218       1.135      yamt 	LIST_REMOVE(ndp, dc_hash);
   1219       1.135      yamt 	LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
   1220       1.135      yamt 
   1221       1.135      yamt 	nfs_putdircache_unlocked(np, ndp);
   1222       1.135      yamt }
   1223       1.135      yamt 
   1224       1.135      yamt void
   1225       1.214       dsl nfs_putdircache(struct nfsnode *np, struct nfsdircache *ndp)
   1226       1.135      yamt {
   1227       1.135      yamt 	int ref;
   1228       1.135      yamt 
   1229       1.135      yamt 	if (ndp == &dzero)
   1230       1.135      yamt 		return;
   1231       1.135      yamt 
   1232       1.135      yamt 	KASSERT(ndp->dc_refcnt > 0);
   1233       1.135      yamt 	NFSDC_LOCK(np);
   1234       1.135      yamt 	ref = --ndp->dc_refcnt;
   1235       1.135      yamt 	NFSDC_UNLOCK(np);
   1236       1.135      yamt 
   1237       1.135      yamt 	if (ref == 0)
   1238       1.196      yamt 		kmem_free(ndp, sizeof(*ndp));
   1239        1.49      fvdl }
   1240        1.49      fvdl 
   1241       1.135      yamt static void
   1242       1.177      yamt nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
   1243       1.135      yamt {
   1244       1.135      yamt 	int ref;
   1245       1.135      yamt 
   1246       1.135      yamt 	NFSDC_ASSERT_LOCKED(np);
   1247       1.135      yamt 
   1248       1.135      yamt 	if (ndp == &dzero)
   1249       1.135      yamt 		return;
   1250       1.135      yamt 
   1251       1.135      yamt 	KASSERT(ndp->dc_refcnt > 0);
   1252       1.135      yamt 	ref = --ndp->dc_refcnt;
   1253       1.135      yamt 	if (ref == 0)
   1254       1.196      yamt 		kmem_free(ndp, sizeof(*ndp));
   1255       1.135      yamt }
   1256        1.46      fvdl 
   1257        1.46      fvdl struct nfsdircache *
   1258       1.214       dsl nfs_searchdircache(struct vnode *vp, off_t off, int do32, int *hashent)
   1259        1.49      fvdl {
   1260        1.49      fvdl 	struct nfsdirhashhead *ndhp;
   1261        1.49      fvdl 	struct nfsdircache *ndp = NULL;
   1262        1.49      fvdl 	struct nfsnode *np = VTONFS(vp);
   1263        1.49      fvdl 	unsigned ent;
   1264        1.49      fvdl 
   1265        1.49      fvdl 	/*
   1266        1.49      fvdl 	 * Zero is always a valid cookie.
   1267        1.49      fvdl 	 */
   1268        1.49      fvdl 	if (off == 0)
   1269       1.149  christos 		/* XXXUNCONST */
   1270       1.149  christos 		return (struct nfsdircache *)__UNCONST(&dzero);
   1271        1.49      fvdl 
   1272       1.134      yamt 	if (!np->n_dircache)
   1273       1.134      yamt 		return NULL;
   1274       1.134      yamt 
   1275        1.49      fvdl 	/*
   1276        1.49      fvdl 	 * We use a 32bit cookie as search key, directly reconstruct
   1277        1.49      fvdl 	 * the hashentry. Else use the hashfunction.
   1278        1.49      fvdl 	 */
   1279        1.49      fvdl 	if (do32) {
   1280        1.49      fvdl 		ent = (u_int32_t)off >> 24;
   1281        1.49      fvdl 		if (ent >= NFS_DIRHASHSIZ)
   1282        1.49      fvdl 			return NULL;
   1283        1.49      fvdl 		ndhp = &np->n_dircache[ent];
   1284        1.49      fvdl 	} else {
   1285        1.49      fvdl 		ndhp = NFSDIRHASH(np, off);
   1286        1.49      fvdl 	}
   1287        1.49      fvdl 
   1288        1.49      fvdl 	if (hashent)
   1289        1.49      fvdl 		*hashent = (int)(ndhp - np->n_dircache);
   1290       1.135      yamt 
   1291       1.135      yamt 	NFSDC_LOCK(np);
   1292        1.49      fvdl 	if (do32) {
   1293       1.113      yamt 		LIST_FOREACH(ndp, ndhp, dc_hash) {
   1294        1.49      fvdl 			if (ndp->dc_cookie32 == (u_int32_t)off) {
   1295        1.49      fvdl 				/*
   1296        1.49      fvdl 				 * An invalidated entry will become the
   1297        1.49      fvdl 				 * start of a new block fetched from
   1298        1.49      fvdl 				 * the server.
   1299        1.49      fvdl 				 */
   1300       1.135      yamt 				if (ndp->dc_flags & NFSDC_INVALID) {
   1301        1.49      fvdl 					ndp->dc_blkcookie = ndp->dc_cookie;
   1302        1.49      fvdl 					ndp->dc_entry = 0;
   1303       1.135      yamt 					ndp->dc_flags &= ~NFSDC_INVALID;
   1304        1.49      fvdl 				}
   1305        1.49      fvdl 				break;
   1306        1.49      fvdl 			}
   1307        1.49      fvdl 		}
   1308        1.49      fvdl 	} else {
   1309       1.113      yamt 		LIST_FOREACH(ndp, ndhp, dc_hash) {
   1310        1.49      fvdl 			if (ndp->dc_cookie == off)
   1311        1.49      fvdl 				break;
   1312       1.113      yamt 		}
   1313        1.49      fvdl 	}
   1314       1.135      yamt 	if (ndp != NULL)
   1315       1.135      yamt 		ndp->dc_refcnt++;
   1316       1.135      yamt 	NFSDC_UNLOCK(np);
   1317        1.49      fvdl 	return ndp;
   1318        1.49      fvdl }
   1319        1.49      fvdl 
   1320        1.49      fvdl 
   1321        1.49      fvdl struct nfsdircache *
   1322       1.171  christos nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
   1323       1.177      yamt     daddr_t blkno)
   1324        1.46      fvdl {
   1325        1.46      fvdl 	struct nfsnode *np = VTONFS(vp);
   1326        1.46      fvdl 	struct nfsdirhashhead *ndhp;
   1327       1.135      yamt 	struct nfsdircache *ndp = NULL;
   1328       1.135      yamt 	struct nfsdircache *newndp = NULL;
   1329        1.49      fvdl 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
   1330       1.161  christos 	int hashent = 0, gen, overwrite;	/* XXX: GCC */
   1331        1.46      fvdl 
   1332       1.135      yamt 	/*
   1333       1.135      yamt 	 * XXX refuse entries for offset 0. amd(8) erroneously sets
   1334       1.135      yamt 	 * cookie 0 for the '.' entry, making this necessary. This
   1335       1.135      yamt 	 * isn't so bad, as 0 is a special case anyway.
   1336       1.135      yamt 	 */
   1337       1.135      yamt 	if (off == 0)
   1338       1.149  christos 		/* XXXUNCONST */
   1339       1.149  christos 		return (struct nfsdircache *)__UNCONST(&dzero);
   1340       1.135      yamt 
   1341        1.49      fvdl 	if (!np->n_dircache)
   1342        1.49      fvdl 		/*
   1343        1.49      fvdl 		 * XXX would like to do this in nfs_nget but vtype
   1344        1.49      fvdl 		 * isn't known at that time.
   1345        1.49      fvdl 		 */
   1346        1.49      fvdl 		nfs_initdircache(vp);
   1347        1.50      fvdl 
   1348       1.120      yamt 	if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
   1349       1.120      yamt 		nfs_initdirxlatecookie(vp);
   1350       1.120      yamt 
   1351       1.135      yamt retry:
   1352        1.49      fvdl 	ndp = nfs_searchdircache(vp, off, 0, &hashent);
   1353        1.49      fvdl 
   1354       1.135      yamt 	NFSDC_LOCK(np);
   1355       1.135      yamt 	if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
   1356        1.49      fvdl 		/*
   1357        1.49      fvdl 		 * Overwriting an old entry. Check if it's the same.
   1358        1.49      fvdl 		 * If so, just return. If not, remove the old entry.
   1359        1.49      fvdl 		 */
   1360        1.49      fvdl 		if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
   1361       1.135      yamt 			goto done;
   1362       1.135      yamt 		nfs_unlinkdircache(np, ndp);
   1363       1.135      yamt 		nfs_putdircache_unlocked(np, ndp);
   1364       1.135      yamt 		ndp = NULL;
   1365        1.46      fvdl 	}
   1366        1.46      fvdl 
   1367        1.49      fvdl 	ndhp = &np->n_dircache[hashent];
   1368        1.46      fvdl 
   1369        1.49      fvdl 	if (!ndp) {
   1370       1.135      yamt 		if (newndp == NULL) {
   1371       1.135      yamt 			NFSDC_UNLOCK(np);
   1372       1.196      yamt 			newndp = kmem_alloc(sizeof(*newndp), KM_SLEEP);
   1373       1.135      yamt 			newndp->dc_refcnt = 1;
   1374       1.135      yamt 			LIST_NEXT(newndp, dc_hash) = (void *)-1;
   1375       1.135      yamt 			goto retry;
   1376       1.135      yamt 		}
   1377       1.135      yamt 		ndp = newndp;
   1378       1.135      yamt 		newndp = NULL;
   1379        1.49      fvdl 		overwrite = 0;
   1380        1.49      fvdl 		if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
   1381        1.49      fvdl 			/*
   1382        1.49      fvdl 			 * We're allocating a new entry, so bump the
   1383        1.49      fvdl 			 * generation number.
   1384        1.49      fvdl 			 */
   1385       1.160  christos 			KASSERT(np->n_dirgens);
   1386        1.49      fvdl 			gen = ++np->n_dirgens[hashent];
   1387        1.49      fvdl 			if (gen == 0) {
   1388        1.49      fvdl 				np->n_dirgens[hashent]++;
   1389        1.49      fvdl 				gen++;
   1390        1.49      fvdl 			}
   1391        1.49      fvdl 			ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
   1392        1.49      fvdl 		}
   1393        1.49      fvdl 	} else
   1394        1.49      fvdl 		overwrite = 1;
   1395        1.46      fvdl 
   1396        1.49      fvdl 	ndp->dc_cookie = off;
   1397        1.49      fvdl 	ndp->dc_blkcookie = blkoff;
   1398        1.46      fvdl 	ndp->dc_entry = en;
   1399       1.137      yamt 	ndp->dc_flags = 0;
   1400        1.46      fvdl 
   1401        1.49      fvdl 	if (overwrite)
   1402       1.135      yamt 		goto done;
   1403        1.49      fvdl 
   1404        1.46      fvdl 	/*
   1405        1.46      fvdl 	 * If the maximum directory cookie cache size has been reached
   1406        1.46      fvdl 	 * for this node, take one off the front. The idea is that
   1407        1.46      fvdl 	 * directories are typically read front-to-back once, so that
   1408        1.46      fvdl 	 * the oldest entries can be thrown away without much performance
   1409        1.46      fvdl 	 * loss.
   1410        1.46      fvdl 	 */
   1411        1.46      fvdl 	if (np->n_dircachesize == NFS_MAXDIRCACHE) {
   1412       1.135      yamt 		nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
   1413        1.46      fvdl 	} else
   1414        1.46      fvdl 		np->n_dircachesize++;
   1415       1.148     perry 
   1416       1.135      yamt 	KASSERT(ndp->dc_refcnt == 1);
   1417        1.46      fvdl 	LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
   1418        1.46      fvdl 	TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
   1419       1.135      yamt 	ndp->dc_refcnt++;
   1420       1.135      yamt done:
   1421       1.135      yamt 	KASSERT(ndp->dc_refcnt > 0);
   1422       1.135      yamt 	NFSDC_UNLOCK(np);
   1423       1.135      yamt 	if (newndp)
   1424       1.135      yamt 		nfs_putdircache(np, newndp);
   1425        1.46      fvdl 	return ndp;
   1426        1.46      fvdl }
   1427        1.46      fvdl 
   1428        1.46      fvdl void
   1429       1.214       dsl nfs_invaldircache(struct vnode *vp, int flags)
   1430        1.46      fvdl {
   1431        1.46      fvdl 	struct nfsnode *np = VTONFS(vp);
   1432        1.46      fvdl 	struct nfsdircache *ndp = NULL;
   1433        1.49      fvdl 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
   1434       1.181   thorpej 	const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
   1435        1.46      fvdl 
   1436        1.46      fvdl #ifdef DIAGNOSTIC
   1437        1.46      fvdl 	if (vp->v_type != VDIR)
   1438        1.46      fvdl 		panic("nfs: invaldircache: not dir");
   1439        1.46      fvdl #endif
   1440        1.46      fvdl 
   1441       1.145      yamt 	if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
   1442       1.145      yamt 		np->n_flag &= ~NEOFVALID;
   1443       1.144      yamt 
   1444        1.46      fvdl 	if (!np->n_dircache)
   1445        1.46      fvdl 		return;
   1446        1.46      fvdl 
   1447       1.135      yamt 	NFSDC_LOCK(np);
   1448        1.49      fvdl 	if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
   1449       1.135      yamt 		while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
   1450       1.135      yamt 			KASSERT(!forcefree || ndp->dc_refcnt == 1);
   1451       1.135      yamt 			nfs_unlinkdircache(np, ndp);
   1452        1.49      fvdl 		}
   1453        1.49      fvdl 		np->n_dircachesize = 0;
   1454        1.49      fvdl 		if (forcefree && np->n_dirgens) {
   1455       1.196      yamt 			kmem_free(np->n_dirgens,
   1456       1.196      yamt 			    NFS_DIRHASHSIZ * sizeof(unsigned));
   1457       1.120      yamt 			np->n_dirgens = NULL;
   1458        1.49      fvdl 		}
   1459        1.49      fvdl 	} else {
   1460       1.135      yamt 		TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
   1461       1.135      yamt 			ndp->dc_flags |= NFSDC_INVALID;
   1462        1.46      fvdl 	}
   1463        1.46      fvdl 
   1464       1.135      yamt 	NFSDC_UNLOCK(np);
   1465        1.46      fvdl }
   1466        1.46      fvdl 
   1467         1.1       cgd /*
   1468        1.35   thorpej  * Called once before VFS init to initialize shared and
   1469        1.35   thorpej  * server-specific data structures.
   1470         1.1       cgd  */
   1471       1.157      yamt static int
   1472       1.155   thorpej nfs_init0(void)
   1473         1.1       cgd {
   1474       1.189        ad 
   1475        1.12   mycroft 	nfsrtt.pos = 0;
   1476         1.1       cgd 	rpc_vers = txdr_unsigned(RPC_VER2);
   1477         1.1       cgd 	rpc_call = txdr_unsigned(RPC_CALL);
   1478         1.1       cgd 	rpc_reply = txdr_unsigned(RPC_REPLY);
   1479         1.1       cgd 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
   1480         1.1       cgd 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
   1481         1.1       cgd 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
   1482        1.12   mycroft 	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
   1483         1.1       cgd 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
   1484        1.25      fvdl 	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
   1485         1.1       cgd 	nfs_prog = txdr_unsigned(NFS_PROG);
   1486       1.182   thorpej 	nfs_true = txdr_unsigned(true);
   1487       1.182   thorpej 	nfs_false = txdr_unsigned(false);
   1488        1.12   mycroft 	nfs_xdrneg1 = txdr_unsigned(-1);
   1489        1.25      fvdl 	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
   1490        1.25      fvdl 	if (nfs_ticks < 1)
   1491        1.25      fvdl 		nfs_ticks = 1;
   1492       1.222       tls 	nfs_xid = cprng_fast32();
   1493       1.164      yamt 	nfsdreq_init();
   1494       1.164      yamt 
   1495         1.1       cgd 	/*
   1496         1.1       cgd 	 * Initialize reply list and start timer
   1497         1.1       cgd 	 */
   1498        1.16   mycroft 	TAILQ_INIT(&nfs_reqq);
   1499       1.191      yamt 	nfs_timer_init();
   1500       1.109      matt 	MOWNER_ATTACH(&nfs_mowner);
   1501       1.106  jdolecek 
   1502       1.157      yamt 	return 0;
   1503         1.1       cgd }
   1504         1.1       cgd 
   1505  1.222.12.1     rmind static volatile uint32_t nfs_mutex;
   1506  1.222.12.1     rmind static uint32_t nfs_refcount;
   1507  1.222.12.1     rmind 
   1508  1.222.12.1     rmind #define nfs_p()	while (atomic_cas_32(&nfs_mutex, 0, 1) == 0) continue;
   1509  1.222.12.1     rmind #define nfs_v()	while (atomic_cas_32(&nfs_mutex, 1, 0) == 1) continue;
   1510  1.222.12.1     rmind 
   1511       1.210        ad /*
   1512       1.210        ad  * This is disgusting, but it must support both modular and monolothic
   1513  1.222.12.1     rmind  * configurations, plus the code is shared between server and client.
   1514  1.222.12.1     rmind  * For monolithic builds NFSSERVER may not imply NFS. Unfortunately we
   1515  1.222.12.1     rmind  * can't use regular mutexes here that would require static initialization
   1516  1.222.12.1     rmind  * and we can get initialized from multiple places, so we improvise.
   1517       1.210        ad  *
   1518       1.210        ad  * Yuck.
   1519       1.210        ad  */
   1520       1.155   thorpej void
   1521       1.155   thorpej nfs_init(void)
   1522       1.155   thorpej {
   1523       1.155   thorpej 
   1524  1.222.12.1     rmind 	nfs_p();
   1525  1.222.12.1     rmind 	if (nfs_refcount++ == 0)
   1526  1.222.12.1     rmind 		nfs_init0();
   1527  1.222.12.1     rmind 	nfs_v();
   1528       1.155   thorpej }
   1529       1.155   thorpej 
   1530       1.210        ad void
   1531       1.210        ad nfs_fini(void)
   1532       1.210        ad {
   1533       1.210        ad 
   1534  1.222.12.1     rmind 	nfs_p();
   1535  1.222.12.1     rmind 	if (--nfs_refcount == 0) {
   1536  1.222.12.1     rmind 		MOWNER_DETACH(&nfs_mowner);
   1537  1.222.12.1     rmind 		nfs_timer_fini();
   1538  1.222.12.1     rmind 		nfsdreq_fini();
   1539  1.222.12.1     rmind 	}
   1540  1.222.12.1     rmind 	nfs_v();
   1541       1.210        ad }
   1542       1.210        ad 
   1543         1.1       cgd /*
   1544       1.118      yamt  * A fiddled version of m_adj() that ensures null fill to a 32-bit
   1545         1.1       cgd  * boundary and only trims off the back end
   1546       1.122      yamt  *
   1547       1.122      yamt  * 1. trim off 'len' bytes as m_adj(mp, -len).
   1548       1.122      yamt  * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
   1549         1.1       cgd  */
   1550        1.12   mycroft void
   1551       1.214       dsl nfs_zeropad(struct mbuf *mp, int len, int nul)
   1552         1.1       cgd {
   1553        1.75  augustss 	struct mbuf *m;
   1554       1.130      yamt 	int count;
   1555         1.1       cgd 
   1556         1.1       cgd 	/*
   1557         1.1       cgd 	 * Trim from tail.  Scan the mbuf chain,
   1558         1.1       cgd 	 * calculating its length and finding the last mbuf.
   1559         1.1       cgd 	 * If the adjustment only affects this mbuf, then just
   1560         1.1       cgd 	 * adjust and return.  Otherwise, rescan and truncate
   1561         1.1       cgd 	 * after the remaining size.
   1562         1.1       cgd 	 */
   1563         1.1       cgd 	count = 0;
   1564         1.1       cgd 	m = mp;
   1565         1.1       cgd 	for (;;) {
   1566         1.1       cgd 		count += m->m_len;
   1567       1.122      yamt 		if (m->m_next == NULL)
   1568         1.1       cgd 			break;
   1569         1.1       cgd 		m = m->m_next;
   1570         1.1       cgd 	}
   1571       1.122      yamt 
   1572       1.122      yamt 	KDASSERT(count >= len);
   1573       1.122      yamt 
   1574       1.122      yamt 	if (m->m_len >= len) {
   1575         1.1       cgd 		m->m_len -= len;
   1576       1.122      yamt 	} else {
   1577       1.122      yamt 		count -= len;
   1578       1.122      yamt 		/*
   1579       1.122      yamt 		 * Correct length for chain is "count".
   1580       1.122      yamt 		 * Find the mbuf with last data, adjust its length,
   1581       1.122      yamt 		 * and toss data from remaining mbufs on chain.
   1582       1.122      yamt 		 */
   1583       1.122      yamt 		for (m = mp; m; m = m->m_next) {
   1584       1.122      yamt 			if (m->m_len >= count) {
   1585       1.122      yamt 				m->m_len = count;
   1586       1.122      yamt 				break;
   1587       1.118      yamt 			}
   1588       1.122      yamt 			count -= m->m_len;
   1589         1.1       cgd 		}
   1590       1.159  christos 		KASSERT(m && m->m_next);
   1591       1.122      yamt 		m_freem(m->m_next);
   1592       1.122      yamt 		m->m_next = NULL;
   1593         1.1       cgd 	}
   1594       1.122      yamt 
   1595       1.130      yamt 	KDASSERT(m->m_next == NULL);
   1596       1.130      yamt 
   1597       1.122      yamt 	/*
   1598       1.122      yamt 	 * zero-padding.
   1599       1.122      yamt 	 */
   1600       1.122      yamt 	if (nul > 0) {
   1601       1.130      yamt 		char *cp;
   1602       1.130      yamt 		int i;
   1603       1.130      yamt 
   1604       1.122      yamt 		if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
   1605       1.122      yamt 			struct mbuf *n;
   1606       1.122      yamt 
   1607       1.122      yamt 			KDASSERT(MLEN >= nul);
   1608       1.122      yamt 			n = m_get(M_WAIT, MT_DATA);
   1609       1.122      yamt 			MCLAIM(n, &nfs_mowner);
   1610       1.122      yamt 			n->m_len = nul;
   1611       1.130      yamt 			n->m_next = NULL;
   1612       1.122      yamt 			m->m_next = n;
   1613       1.183  christos 			cp = mtod(n, void *);
   1614       1.122      yamt 		} else {
   1615       1.183  christos 			cp = mtod(m, char *) + m->m_len;
   1616       1.122      yamt 			m->m_len += nul;
   1617         1.1       cgd 		}
   1618       1.122      yamt 		for (i = 0; i < nul; i++)
   1619       1.122      yamt 			*cp++ = '\0';
   1620         1.1       cgd 	}
   1621       1.122      yamt 	return;
   1622         1.1       cgd }
   1623         1.1       cgd 
   1624         1.1       cgd /*
   1625        1.25      fvdl  * Make these functions instead of macros, so that the kernel text size
   1626        1.25      fvdl  * doesn't get too big...
   1627        1.25      fvdl  */
   1628        1.25      fvdl void
   1629       1.214       dsl nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, struct vattr *before_vap, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
   1630        1.25      fvdl {
   1631       1.109      matt 	struct mbuf *mb = *mbp;
   1632        1.75  augustss 	char *bpos = *bposp;
   1633        1.75  augustss 	u_int32_t *tl;
   1634        1.25      fvdl 
   1635        1.25      fvdl 	if (before_ret) {
   1636        1.25      fvdl 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
   1637        1.25      fvdl 		*tl = nfs_false;
   1638        1.25      fvdl 	} else {
   1639        1.25      fvdl 		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
   1640        1.25      fvdl 		*tl++ = nfs_true;
   1641        1.66      fair 		txdr_hyper(before_vap->va_size, tl);
   1642        1.25      fvdl 		tl += 2;
   1643        1.25      fvdl 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
   1644        1.25      fvdl 		tl += 2;
   1645        1.25      fvdl 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
   1646        1.25      fvdl 	}
   1647        1.25      fvdl 	*bposp = bpos;
   1648        1.25      fvdl 	*mbp = mb;
   1649        1.25      fvdl 	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
   1650        1.25      fvdl }
   1651        1.25      fvdl 
   1652        1.25      fvdl void
   1653       1.214       dsl nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
   1654        1.25      fvdl {
   1655       1.109      matt 	struct mbuf *mb = *mbp;
   1656        1.75  augustss 	char *bpos = *bposp;
   1657        1.75  augustss 	u_int32_t *tl;
   1658        1.75  augustss 	struct nfs_fattr *fp;
   1659        1.25      fvdl 
   1660        1.25      fvdl 	if (after_ret) {
   1661        1.25      fvdl 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
   1662        1.25      fvdl 		*tl = nfs_false;
   1663        1.25      fvdl 	} else {
   1664        1.25      fvdl 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
   1665        1.25      fvdl 		*tl++ = nfs_true;
   1666        1.25      fvdl 		fp = (struct nfs_fattr *)tl;
   1667        1.25      fvdl 		nfsm_srvfattr(nfsd, after_vap, fp);
   1668        1.25      fvdl 	}
   1669        1.25      fvdl 	*mbp = mb;
   1670        1.25      fvdl 	*bposp = bpos;
   1671        1.25      fvdl }
   1672        1.25      fvdl 
   1673        1.25      fvdl void
   1674       1.214       dsl nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, struct nfs_fattr *fp)
   1675        1.25      fvdl {
   1676        1.25      fvdl 
   1677        1.25      fvdl 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
   1678        1.25      fvdl 	fp->fa_uid = txdr_unsigned(vap->va_uid);
   1679        1.25      fvdl 	fp->fa_gid = txdr_unsigned(vap->va_gid);
   1680        1.25      fvdl 	if (nfsd->nd_flag & ND_NFSV3) {
   1681        1.25      fvdl 		fp->fa_type = vtonfsv3_type(vap->va_type);
   1682        1.25      fvdl 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
   1683        1.66      fair 		txdr_hyper(vap->va_size, &fp->fa3_size);
   1684        1.66      fair 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
   1685        1.25      fvdl 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
   1686        1.25      fvdl 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
   1687        1.25      fvdl 		fp->fa3_fsid.nfsuquad[0] = 0;
   1688        1.25      fvdl 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
   1689       1.151      yamt 		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
   1690        1.25      fvdl 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
   1691        1.25      fvdl 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
   1692        1.25      fvdl 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
   1693        1.25      fvdl 	} else {
   1694        1.25      fvdl 		fp->fa_type = vtonfsv2_type(vap->va_type);
   1695        1.25      fvdl 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
   1696        1.25      fvdl 		fp->fa2_size = txdr_unsigned(vap->va_size);
   1697        1.25      fvdl 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
   1698        1.25      fvdl 		if (vap->va_type == VFIFO)
   1699        1.25      fvdl 			fp->fa2_rdev = 0xffffffff;
   1700        1.25      fvdl 		else
   1701        1.25      fvdl 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
   1702        1.25      fvdl 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
   1703        1.25      fvdl 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
   1704        1.25      fvdl 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
   1705        1.25      fvdl 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
   1706        1.25      fvdl 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
   1707        1.25      fvdl 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
   1708        1.25      fvdl 	}
   1709        1.25      fvdl }
   1710        1.25      fvdl 
   1711         1.1       cgd /*
   1712       1.182   thorpej  * This function compares two net addresses by family and returns true
   1713        1.12   mycroft  * if they are the same host.
   1714       1.182   thorpej  * If there is any doubt, return false.
   1715        1.12   mycroft  * The AF_INET family is handled as a special case so that address mbufs
   1716        1.12   mycroft  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
   1717         1.1       cgd  */
   1718        1.24  christos int
   1719       1.214       dsl netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
   1720         1.1       cgd {
   1721        1.75  augustss 	struct sockaddr_in *inetaddr;
   1722         1.1       cgd 
   1723        1.12   mycroft 	switch (family) {
   1724        1.12   mycroft 	case AF_INET:
   1725        1.12   mycroft 		inetaddr = mtod(nam, struct sockaddr_in *);
   1726        1.12   mycroft 		if (inetaddr->sin_family == AF_INET &&
   1727        1.12   mycroft 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
   1728        1.12   mycroft 			return (1);
   1729        1.12   mycroft 		break;
   1730        1.76      fvdl 	case AF_INET6:
   1731        1.76      fvdl 	    {
   1732        1.76      fvdl 		struct sockaddr_in6 *sin6_1, *sin6_2;
   1733        1.76      fvdl 
   1734        1.76      fvdl 		sin6_1 = mtod(nam, struct sockaddr_in6 *);
   1735        1.76      fvdl 		sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
   1736        1.76      fvdl 		if (sin6_1->sin6_family == AF_INET6 &&
   1737        1.76      fvdl 		    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
   1738        1.76      fvdl 			return 1;
   1739        1.76      fvdl 	    }
   1740        1.12   mycroft 	default:
   1741        1.12   mycroft 		break;
   1742        1.12   mycroft 	};
   1743        1.12   mycroft 	return (0);
   1744        1.25      fvdl }
   1745        1.25      fvdl 
   1746        1.25      fvdl /*
   1747        1.25      fvdl  * The write verifier has changed (probably due to a server reboot), so all
   1748       1.114      yamt  * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
   1749       1.117      yamt  * as dirty or are being written out just now, all this takes is clearing
   1750       1.117      yamt  * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
   1751       1.117      yamt  * the mount point.
   1752        1.25      fvdl  */
   1753        1.25      fvdl void
   1754       1.214       dsl nfs_clearcommit(struct mount *mp)
   1755        1.25      fvdl {
   1756        1.89       chs 	struct vnode *vp;
   1757  1.222.12.1     rmind 	struct vnode_iterator *marker;
   1758        1.83      fvdl 	struct nfsnode *np;
   1759        1.89       chs 	struct vm_page *pg;
   1760       1.116      yamt 	struct nfsmount *nmp = VFSTONFS(mp);
   1761       1.116      yamt 
   1762       1.180      yamt 	rw_enter(&nmp->nm_writeverflock, RW_WRITER);
   1763  1.222.12.1     rmind 	vfs_vnode_iterator_init(mp, &marker);
   1764  1.222.12.1     rmind 	while (vfs_vnode_iterator_next(marker, &vp)) {
   1765       1.221     rmind 		mutex_enter(vp->v_interlock);
   1766  1.222.12.1     rmind 		np = VTONFS(vp);
   1767  1.222.12.1     rmind 		if (vp->v_type != VREG || vp->v_mount != mp || np == NULL) {
   1768       1.221     rmind 			mutex_exit(vp->v_interlock);
   1769  1.222.12.1     rmind 			vrele(vp);
   1770       1.217      yamt 			continue;
   1771       1.217      yamt 		}
   1772        1.83      fvdl 		np->n_pushlo = np->n_pushhi = np->n_pushedlo =
   1773        1.83      fvdl 		    np->n_pushedhi = 0;
   1774        1.83      fvdl 		np->n_commitflags &=
   1775        1.83      fvdl 		    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
   1776       1.204        ad 		TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) {
   1777        1.89       chs 			pg->flags &= ~PG_NEEDCOMMIT;
   1778        1.25      fvdl 		}
   1779       1.221     rmind 		mutex_exit(vp->v_interlock);
   1780  1.222.12.1     rmind 		vrele(vp);
   1781        1.25      fvdl 	}
   1782  1.222.12.1     rmind 	vfs_vnode_iterator_destroy(marker);
   1783       1.186      yamt 	mutex_enter(&nmp->nm_lock);
   1784       1.116      yamt 	nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
   1785       1.186      yamt 	mutex_exit(&nmp->nm_lock);
   1786       1.180      yamt 	rw_exit(&nmp->nm_writeverflock);
   1787        1.83      fvdl }
   1788        1.83      fvdl 
   1789        1.83      fvdl void
   1790       1.214       dsl nfs_merge_commit_ranges(struct vnode *vp)
   1791        1.83      fvdl {
   1792        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1793       1.112      yamt 
   1794       1.112      yamt 	KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
   1795        1.83      fvdl 
   1796        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
   1797        1.83      fvdl 		np->n_pushedlo = np->n_pushlo;
   1798        1.83      fvdl 		np->n_pushedhi = np->n_pushhi;
   1799        1.83      fvdl 		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
   1800        1.83      fvdl 	} else {
   1801        1.83      fvdl 		if (np->n_pushlo < np->n_pushedlo)
   1802        1.83      fvdl 			np->n_pushedlo = np->n_pushlo;
   1803        1.83      fvdl 		if (np->n_pushhi > np->n_pushedhi)
   1804        1.83      fvdl 			np->n_pushedhi = np->n_pushhi;
   1805        1.83      fvdl 	}
   1806        1.83      fvdl 
   1807        1.83      fvdl 	np->n_pushlo = np->n_pushhi = 0;
   1808        1.83      fvdl 	np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
   1809        1.83      fvdl 
   1810       1.111      yamt #ifdef NFS_DEBUG_COMMIT
   1811        1.83      fvdl 	printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
   1812        1.83      fvdl 	    (unsigned)np->n_pushedhi);
   1813        1.83      fvdl #endif
   1814        1.83      fvdl }
   1815        1.83      fvdl 
   1816        1.83      fvdl int
   1817       1.215       dsl nfs_in_committed_range(struct vnode *vp, off_t off, off_t len)
   1818        1.83      fvdl {
   1819        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1820        1.83      fvdl 	off_t lo, hi;
   1821        1.83      fvdl 
   1822        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
   1823        1.83      fvdl 		return 0;
   1824        1.89       chs 	lo = off;
   1825        1.89       chs 	hi = lo + len;
   1826        1.83      fvdl 
   1827        1.83      fvdl 	return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
   1828        1.83      fvdl }
   1829        1.83      fvdl 
   1830        1.83      fvdl int
   1831       1.215       dsl nfs_in_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
   1832        1.83      fvdl {
   1833        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1834        1.83      fvdl 	off_t lo, hi;
   1835        1.83      fvdl 
   1836        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
   1837        1.83      fvdl 		return 0;
   1838        1.89       chs 	lo = off;
   1839        1.89       chs 	hi = lo + len;
   1840        1.83      fvdl 
   1841        1.83      fvdl 	return (lo >= np->n_pushlo && hi <= np->n_pushhi);
   1842        1.83      fvdl }
   1843        1.83      fvdl 
   1844        1.83      fvdl void
   1845       1.215       dsl nfs_add_committed_range(struct vnode *vp, off_t off, off_t len)
   1846        1.83      fvdl {
   1847        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1848        1.83      fvdl 	off_t lo, hi;
   1849        1.83      fvdl 
   1850        1.89       chs 	lo = off;
   1851        1.89       chs 	hi = lo + len;
   1852        1.83      fvdl 
   1853        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
   1854        1.83      fvdl 		np->n_pushedlo = lo;
   1855        1.83      fvdl 		np->n_pushedhi = hi;
   1856        1.83      fvdl 		np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
   1857        1.83      fvdl 	} else {
   1858        1.83      fvdl 		if (hi > np->n_pushedhi)
   1859        1.83      fvdl 			np->n_pushedhi = hi;
   1860        1.83      fvdl 		if (lo < np->n_pushedlo)
   1861        1.83      fvdl 			np->n_pushedlo = lo;
   1862        1.83      fvdl 	}
   1863       1.111      yamt #ifdef NFS_DEBUG_COMMIT
   1864        1.83      fvdl 	printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
   1865        1.83      fvdl 	    (unsigned)np->n_pushedhi);
   1866        1.83      fvdl #endif
   1867        1.83      fvdl }
   1868        1.83      fvdl 
   1869        1.83      fvdl void
   1870       1.215       dsl nfs_del_committed_range(struct vnode *vp, off_t off, off_t len)
   1871        1.83      fvdl {
   1872        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1873        1.83      fvdl 	off_t lo, hi;
   1874        1.83      fvdl 
   1875        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
   1876        1.83      fvdl 		return;
   1877        1.83      fvdl 
   1878        1.89       chs 	lo = off;
   1879        1.89       chs 	hi = lo + len;
   1880        1.83      fvdl 
   1881        1.83      fvdl 	if (lo > np->n_pushedhi || hi < np->n_pushedlo)
   1882        1.83      fvdl 		return;
   1883        1.83      fvdl 	if (lo <= np->n_pushedlo)
   1884        1.83      fvdl 		np->n_pushedlo = hi;
   1885        1.83      fvdl 	else if (hi >= np->n_pushedhi)
   1886        1.83      fvdl 		np->n_pushedhi = lo;
   1887        1.83      fvdl 	else {
   1888        1.83      fvdl 		/*
   1889        1.83      fvdl 		 * XXX There's only one range. If the deleted range
   1890        1.83      fvdl 		 * is in the middle, pick the largest of the
   1891        1.83      fvdl 		 * contiguous ranges that it leaves.
   1892        1.83      fvdl 		 */
   1893        1.83      fvdl 		if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
   1894        1.83      fvdl 			np->n_pushedhi = lo;
   1895        1.83      fvdl 		else
   1896        1.83      fvdl 			np->n_pushedlo = hi;
   1897        1.83      fvdl 	}
   1898       1.111      yamt #ifdef NFS_DEBUG_COMMIT
   1899        1.83      fvdl 	printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
   1900        1.83      fvdl 	    (unsigned)np->n_pushedhi);
   1901        1.83      fvdl #endif
   1902        1.83      fvdl }
   1903        1.83      fvdl 
   1904        1.83      fvdl void
   1905       1.215       dsl nfs_add_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
   1906        1.83      fvdl {
   1907        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1908        1.83      fvdl 	off_t lo, hi;
   1909        1.83      fvdl 
   1910        1.89       chs 	lo = off;
   1911        1.89       chs 	hi = lo + len;
   1912        1.83      fvdl 
   1913        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
   1914        1.83      fvdl 		np->n_pushlo = lo;
   1915        1.83      fvdl 		np->n_pushhi = hi;
   1916        1.83      fvdl 		np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
   1917        1.83      fvdl 	} else {
   1918        1.83      fvdl 		if (lo < np->n_pushlo)
   1919        1.83      fvdl 			np->n_pushlo = lo;
   1920        1.83      fvdl 		if (hi > np->n_pushhi)
   1921        1.83      fvdl 			np->n_pushhi = hi;
   1922        1.83      fvdl 	}
   1923       1.111      yamt #ifdef NFS_DEBUG_COMMIT
   1924        1.83      fvdl 	printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
   1925        1.83      fvdl 	    (unsigned)np->n_pushhi);
   1926        1.83      fvdl #endif
   1927        1.83      fvdl }
   1928        1.83      fvdl 
   1929        1.83      fvdl void
   1930       1.215       dsl nfs_del_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
   1931        1.83      fvdl {
   1932        1.83      fvdl 	struct nfsnode *np = VTONFS(vp);
   1933        1.83      fvdl 	off_t lo, hi;
   1934        1.83      fvdl 
   1935        1.83      fvdl 	if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
   1936        1.83      fvdl 		return;
   1937        1.83      fvdl 
   1938        1.89       chs 	lo = off;
   1939        1.89       chs 	hi = lo + len;
   1940        1.83      fvdl 
   1941        1.83      fvdl 	if (lo > np->n_pushhi || hi < np->n_pushlo)
   1942        1.83      fvdl 		return;
   1943        1.83      fvdl 
   1944        1.83      fvdl 	if (lo <= np->n_pushlo)
   1945        1.83      fvdl 		np->n_pushlo = hi;
   1946        1.83      fvdl 	else if (hi >= np->n_pushhi)
   1947        1.83      fvdl 		np->n_pushhi = lo;
   1948        1.83      fvdl 	else {
   1949        1.83      fvdl 		/*
   1950        1.83      fvdl 		 * XXX There's only one range. If the deleted range
   1951        1.83      fvdl 		 * is in the middle, pick the largest of the
   1952        1.83      fvdl 		 * contiguous ranges that it leaves.
   1953        1.83      fvdl 		 */
   1954        1.83      fvdl 		if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
   1955        1.83      fvdl 			np->n_pushhi = lo;
   1956        1.83      fvdl 		else
   1957        1.83      fvdl 			np->n_pushlo = hi;
   1958        1.83      fvdl 	}
   1959       1.111      yamt #ifdef NFS_DEBUG_COMMIT
   1960        1.83      fvdl 	printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
   1961        1.83      fvdl 	    (unsigned)np->n_pushhi);
   1962        1.83      fvdl #endif
   1963        1.25      fvdl }
   1964        1.25      fvdl 
   1965        1.25      fvdl /*
   1966        1.25      fvdl  * Map errnos to NFS error numbers. For Version 3 also filter out error
   1967        1.25      fvdl  * numbers not specified for the associated procedure.
   1968        1.25      fvdl  */
   1969        1.25      fvdl int
   1970       1.214       dsl nfsrv_errmap(struct nfsrv_descript *nd, int err)
   1971        1.25      fvdl {
   1972        1.90  jdolecek 	const short *defaulterrp, *errp;
   1973        1.25      fvdl 
   1974        1.25      fvdl 	if (nd->nd_flag & ND_NFSV3) {
   1975        1.25      fvdl 	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
   1976        1.25      fvdl 		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
   1977        1.25      fvdl 		while (*++errp) {
   1978        1.25      fvdl 			if (*errp == err)
   1979        1.25      fvdl 				return (err);
   1980        1.25      fvdl 			else if (*errp > err)
   1981        1.25      fvdl 				break;
   1982        1.25      fvdl 		}
   1983        1.25      fvdl 		return ((int)*defaulterrp);
   1984        1.25      fvdl 	    } else
   1985        1.25      fvdl 		return (err & 0xffff);
   1986        1.25      fvdl 	}
   1987        1.25      fvdl 	if (err <= ELAST)
   1988        1.25      fvdl 		return ((int)nfsrv_v2errmap[err - 1]);
   1989        1.25      fvdl 	return (NFSERR_IO);
   1990        1.25      fvdl }
   1991        1.25      fvdl 
   1992       1.126      yamt u_int32_t
   1993       1.216    cegger nfs_getxid(void)
   1994       1.126      yamt {
   1995       1.126      yamt 	u_int32_t newxid;
   1996       1.126      yamt 
   1997       1.207     pooka 	/* get next xid.  skip 0 */
   1998       1.207     pooka 	do {
   1999       1.207     pooka 		newxid = atomic_inc_32_nv(&nfs_xid);
   2000       1.207     pooka 	} while (__predict_false(newxid == 0));
   2001       1.126      yamt 
   2002       1.126      yamt 	return txdr_unsigned(newxid);
   2003       1.126      yamt }
   2004       1.126      yamt 
   2005       1.126      yamt /*
   2006       1.126      yamt  * assign a new xid for existing request.
   2007       1.126      yamt  * used for NFSERR_JUKEBOX handling.
   2008       1.126      yamt  */
   2009       1.126      yamt void
   2010       1.126      yamt nfs_renewxid(struct nfsreq *req)
   2011       1.126      yamt {
   2012       1.126      yamt 	u_int32_t xid;
   2013       1.126      yamt 	int off;
   2014       1.126      yamt 
   2015       1.126      yamt 	xid = nfs_getxid();
   2016       1.126      yamt 	if (req->r_nmp->nm_sotype == SOCK_STREAM)
   2017       1.126      yamt 		off = sizeof(u_int32_t); /* RPC record mark */
   2018       1.126      yamt 	else
   2019       1.126      yamt 		off = 0;
   2020       1.126      yamt 
   2021       1.126      yamt 	m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
   2022       1.126      yamt 	req->r_xid = xid;
   2023         1.1       cgd }
   2024