nfs_srvsubs.c revision 9336
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Rick Macklem at The University of Guelph. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 361541Srgrimes * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 379336Sdfr * $Id: nfs_subs.c,v 1.16 1995/06/14 06:23:38 joerg Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes/* 411541Srgrimes * These functions support the macros and help fiddle mbuf chains for 421541Srgrimes * the nfs op functions. They do things like create the rpc header and 431541Srgrimes * copy data between mbuf chains and uio lists. 441541Srgrimes */ 451541Srgrimes#include <sys/param.h> 461541Srgrimes#include <sys/proc.h> 471541Srgrimes#include <sys/systm.h> 481541Srgrimes#include <sys/kernel.h> 491541Srgrimes#include <sys/mount.h> 501541Srgrimes#include <sys/vnode.h> 511541Srgrimes#include <sys/namei.h> 521541Srgrimes#include <sys/mbuf.h> 531541Srgrimes#include <sys/socket.h> 541541Srgrimes#include <sys/stat.h> 559336Sdfr#include <sys/malloc.h> 562997Swollman#ifdef VFS_LKM 572997Swollman#include <sys/sysent.h> 582997Swollman#include <sys/syscall.h> 592997Swollman#endif 601541Srgrimes 613305Sphk#include <vm/vm.h> 623305Sphk 631541Srgrimes#include <nfs/rpcv2.h> 649336Sdfr#include <nfs/nfsproto.h> 651541Srgrimes#include <nfs/nfsnode.h> 661541Srgrimes#include <nfs/nfs.h> 671541Srgrimes#include <nfs/xdr_subs.h> 681541Srgrimes#include <nfs/nfsm_subs.h> 691541Srgrimes#include <nfs/nfsmount.h> 701541Srgrimes#include <nfs/nqnfs.h> 711541Srgrimes#include <nfs/nfsrtt.h> 721541Srgrimes 731541Srgrimes#include <miscfs/specfs/specdev.h> 741541Srgrimes 756420Sphk#include <vm/vnode_pager.h> 766420Sphk 771541Srgrimes#include <netinet/in.h> 781541Srgrimes#ifdef ISO 791541Srgrimes#include <netiso/iso.h> 801541Srgrimes#endif 811541Srgrimes 821541Srgrimes/* 831541Srgrimes * Data items converted to xdr at startup, since they are constant 841541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 851541Srgrimes */ 861541Srgrimesu_long nfs_xdrneg1; 871541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 889336Sdfr rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 891541Srgrimes rpc_auth_kerb; 909336Sdfru_long nfs_prog, nqnfs_prog, nfs_true, nfs_false; 911541Srgrimes 921541Srgrimes/* And other global data */ 931541Srgrimesstatic u_long nfs_xid = 0; 949336Sdfrenum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 959336Sdfrenum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 969336Sdfrint nfs_ticks; 979336Sdfr 989336Sdfr/* 999336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1009336Sdfr */ 1019336Sdfrint nfsv3_procid[NFS_NPROCS] = { 1029336Sdfr NFSPROC_NULL, 1039336Sdfr NFSPROC_GETATTR, 1049336Sdfr NFSPROC_SETATTR, 1059336Sdfr NFSPROC_NOOP, 1069336Sdfr NFSPROC_LOOKUP, 1079336Sdfr NFSPROC_READLINK, 1089336Sdfr NFSPROC_READ, 1099336Sdfr NFSPROC_NOOP, 1109336Sdfr NFSPROC_WRITE, 1119336Sdfr NFSPROC_CREATE, 1129336Sdfr NFSPROC_REMOVE, 1139336Sdfr NFSPROC_RENAME, 1149336Sdfr NFSPROC_LINK, 1159336Sdfr NFSPROC_SYMLINK, 1169336Sdfr NFSPROC_MKDIR, 1179336Sdfr NFSPROC_RMDIR, 1189336Sdfr NFSPROC_READDIR, 1199336Sdfr NFSPROC_FSSTAT, 1209336Sdfr NFSPROC_NOOP, 1219336Sdfr NFSPROC_NOOP, 1229336Sdfr NFSPROC_NOOP, 1239336Sdfr NFSPROC_NOOP, 1249336Sdfr NFSPROC_NOOP, 1259336Sdfr NFSPROC_NOOP, 1269336Sdfr NFSPROC_NOOP, 1279336Sdfr NFSPROC_NOOP 1289336Sdfr}; 1299336Sdfr 1309336Sdfr/* 1319336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1329336Sdfr */ 1339336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1349336Sdfr NFSV2PROC_NULL, 1359336Sdfr NFSV2PROC_GETATTR, 1369336Sdfr NFSV2PROC_SETATTR, 1379336Sdfr NFSV2PROC_LOOKUP, 1389336Sdfr NFSV2PROC_NOOP, 1399336Sdfr NFSV2PROC_READLINK, 1409336Sdfr NFSV2PROC_READ, 1419336Sdfr NFSV2PROC_WRITE, 1429336Sdfr NFSV2PROC_CREATE, 1439336Sdfr NFSV2PROC_MKDIR, 1449336Sdfr NFSV2PROC_SYMLINK, 1459336Sdfr NFSV2PROC_CREATE, 1469336Sdfr NFSV2PROC_REMOVE, 1479336Sdfr NFSV2PROC_RMDIR, 1489336Sdfr NFSV2PROC_RENAME, 1499336Sdfr NFSV2PROC_LINK, 1509336Sdfr NFSV2PROC_READDIR, 1519336Sdfr NFSV2PROC_NOOP, 1529336Sdfr NFSV2PROC_STATFS, 1539336Sdfr NFSV2PROC_NOOP, 1549336Sdfr NFSV2PROC_NOOP, 1559336Sdfr NFSV2PROC_NOOP, 1569336Sdfr NFSV2PROC_NOOP, 1579336Sdfr NFSV2PROC_NOOP, 1589336Sdfr NFSV2PROC_NOOP, 1599336Sdfr NFSV2PROC_NOOP, 1609336Sdfr}; 1619336Sdfr 1629336Sdfr/* 1639336Sdfr * Maps errno values to nfs error numbers. 1649336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1659336Sdfr * RFC 1094. 1669336Sdfr */ 1679336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1689336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1699336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1709336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1719336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 1729336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1739336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 1749336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1759336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1769336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1779336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1789336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1799336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1809336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 1819336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 1829336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1839336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1849336Sdfr NFSERR_IO, 1859336Sdfr}; 1869336Sdfr 1879336Sdfr/* 1889336Sdfr * Maps errno values to nfs error numbers. 1899336Sdfr * Although it is not obvious whether or not NFS clients really care if 1909336Sdfr * a returned error value is in the specified list for the procedure, the 1919336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 1929336Sdfr * X/Open XNFS document is the only specification that defines error values 1939336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 1949336Sdfr * so I have decided to not do this for Version 2. 1959336Sdfr * The first entry is the default error return and the rest are the valid 1969336Sdfr * errors for that RPC in increasing numeric order. 1979336Sdfr */ 1989336Sdfrstatic short nfsv3err_null[] = { 1999336Sdfr 0, 2009336Sdfr 0, 2019336Sdfr}; 2029336Sdfr 2039336Sdfrstatic short nfsv3err_getattr[] = { 2049336Sdfr NFSERR_IO, 2059336Sdfr NFSERR_IO, 2069336Sdfr NFSERR_STALE, 2079336Sdfr NFSERR_BADHANDLE, 2089336Sdfr NFSERR_SERVERFAULT, 2099336Sdfr 0, 2109336Sdfr}; 2119336Sdfr 2129336Sdfrstatic short nfsv3err_setattr[] = { 2139336Sdfr NFSERR_IO, 2149336Sdfr NFSERR_PERM, 2159336Sdfr NFSERR_IO, 2169336Sdfr NFSERR_ACCES, 2179336Sdfr NFSERR_INVAL, 2189336Sdfr NFSERR_NOSPC, 2199336Sdfr NFSERR_ROFS, 2209336Sdfr NFSERR_DQUOT, 2219336Sdfr NFSERR_STALE, 2229336Sdfr NFSERR_BADHANDLE, 2239336Sdfr NFSERR_NOT_SYNC, 2249336Sdfr NFSERR_SERVERFAULT, 2259336Sdfr 0, 2269336Sdfr}; 2279336Sdfr 2289336Sdfrstatic short nfsv3err_lookup[] = { 2299336Sdfr NFSERR_IO, 2309336Sdfr NFSERR_NOENT, 2319336Sdfr NFSERR_IO, 2329336Sdfr NFSERR_ACCES, 2339336Sdfr NFSERR_NOTDIR, 2349336Sdfr NFSERR_NAMETOL, 2359336Sdfr NFSERR_STALE, 2369336Sdfr NFSERR_BADHANDLE, 2379336Sdfr NFSERR_SERVERFAULT, 2389336Sdfr 0, 2399336Sdfr}; 2409336Sdfr 2419336Sdfrstatic short nfsv3err_access[] = { 2429336Sdfr NFSERR_IO, 2439336Sdfr NFSERR_IO, 2449336Sdfr NFSERR_STALE, 2459336Sdfr NFSERR_BADHANDLE, 2469336Sdfr NFSERR_SERVERFAULT, 2479336Sdfr 0, 2489336Sdfr}; 2499336Sdfr 2509336Sdfrstatic short nfsv3err_readlink[] = { 2519336Sdfr NFSERR_IO, 2529336Sdfr NFSERR_IO, 2539336Sdfr NFSERR_ACCES, 2549336Sdfr NFSERR_INVAL, 2559336Sdfr NFSERR_STALE, 2569336Sdfr NFSERR_BADHANDLE, 2579336Sdfr NFSERR_NOTSUPP, 2589336Sdfr NFSERR_SERVERFAULT, 2599336Sdfr 0, 2609336Sdfr}; 2619336Sdfr 2629336Sdfrstatic short nfsv3err_read[] = { 2639336Sdfr NFSERR_IO, 2649336Sdfr NFSERR_IO, 2659336Sdfr NFSERR_NXIO, 2669336Sdfr NFSERR_ACCES, 2679336Sdfr NFSERR_INVAL, 2689336Sdfr NFSERR_STALE, 2699336Sdfr NFSERR_BADHANDLE, 2709336Sdfr NFSERR_SERVERFAULT, 2719336Sdfr 0, 2729336Sdfr}; 2739336Sdfr 2749336Sdfrstatic short nfsv3err_write[] = { 2759336Sdfr NFSERR_IO, 2769336Sdfr NFSERR_IO, 2779336Sdfr NFSERR_ACCES, 2789336Sdfr NFSERR_INVAL, 2799336Sdfr NFSERR_FBIG, 2809336Sdfr NFSERR_NOSPC, 2819336Sdfr NFSERR_ROFS, 2829336Sdfr NFSERR_DQUOT, 2839336Sdfr NFSERR_STALE, 2849336Sdfr NFSERR_BADHANDLE, 2859336Sdfr NFSERR_SERVERFAULT, 2869336Sdfr 0, 2879336Sdfr}; 2889336Sdfr 2899336Sdfrstatic short nfsv3err_create[] = { 2909336Sdfr NFSERR_IO, 2919336Sdfr NFSERR_IO, 2929336Sdfr NFSERR_ACCES, 2939336Sdfr NFSERR_EXIST, 2949336Sdfr NFSERR_NOTDIR, 2959336Sdfr NFSERR_NOSPC, 2969336Sdfr NFSERR_ROFS, 2979336Sdfr NFSERR_NAMETOL, 2989336Sdfr NFSERR_DQUOT, 2999336Sdfr NFSERR_STALE, 3009336Sdfr NFSERR_BADHANDLE, 3019336Sdfr NFSERR_NOTSUPP, 3029336Sdfr NFSERR_SERVERFAULT, 3039336Sdfr 0, 3049336Sdfr}; 3059336Sdfr 3069336Sdfrstatic short nfsv3err_mkdir[] = { 3079336Sdfr NFSERR_IO, 3089336Sdfr NFSERR_IO, 3099336Sdfr NFSERR_ACCES, 3109336Sdfr NFSERR_EXIST, 3119336Sdfr NFSERR_NOTDIR, 3129336Sdfr NFSERR_NOSPC, 3139336Sdfr NFSERR_ROFS, 3149336Sdfr NFSERR_NAMETOL, 3159336Sdfr NFSERR_DQUOT, 3169336Sdfr NFSERR_STALE, 3179336Sdfr NFSERR_BADHANDLE, 3189336Sdfr NFSERR_NOTSUPP, 3199336Sdfr NFSERR_SERVERFAULT, 3209336Sdfr 0, 3219336Sdfr}; 3229336Sdfr 3239336Sdfrstatic short nfsv3err_symlink[] = { 3249336Sdfr NFSERR_IO, 3259336Sdfr NFSERR_IO, 3269336Sdfr NFSERR_ACCES, 3279336Sdfr NFSERR_EXIST, 3289336Sdfr NFSERR_NOTDIR, 3299336Sdfr NFSERR_NOSPC, 3309336Sdfr NFSERR_ROFS, 3319336Sdfr NFSERR_NAMETOL, 3329336Sdfr NFSERR_DQUOT, 3339336Sdfr NFSERR_STALE, 3349336Sdfr NFSERR_BADHANDLE, 3359336Sdfr NFSERR_NOTSUPP, 3369336Sdfr NFSERR_SERVERFAULT, 3379336Sdfr 0, 3389336Sdfr}; 3399336Sdfr 3409336Sdfrstatic short nfsv3err_mknod[] = { 3419336Sdfr NFSERR_IO, 3429336Sdfr NFSERR_IO, 3439336Sdfr NFSERR_ACCES, 3449336Sdfr NFSERR_EXIST, 3459336Sdfr NFSERR_NOTDIR, 3469336Sdfr NFSERR_NOSPC, 3479336Sdfr NFSERR_ROFS, 3489336Sdfr NFSERR_NAMETOL, 3499336Sdfr NFSERR_DQUOT, 3509336Sdfr NFSERR_STALE, 3519336Sdfr NFSERR_BADHANDLE, 3529336Sdfr NFSERR_NOTSUPP, 3539336Sdfr NFSERR_SERVERFAULT, 3549336Sdfr NFSERR_BADTYPE, 3559336Sdfr 0, 3569336Sdfr}; 3579336Sdfr 3589336Sdfrstatic short nfsv3err_remove[] = { 3599336Sdfr NFSERR_IO, 3609336Sdfr NFSERR_NOENT, 3619336Sdfr NFSERR_IO, 3629336Sdfr NFSERR_ACCES, 3639336Sdfr NFSERR_NOTDIR, 3649336Sdfr NFSERR_ROFS, 3659336Sdfr NFSERR_NAMETOL, 3669336Sdfr NFSERR_STALE, 3679336Sdfr NFSERR_BADHANDLE, 3689336Sdfr NFSERR_SERVERFAULT, 3699336Sdfr 0, 3709336Sdfr}; 3719336Sdfr 3729336Sdfrstatic short nfsv3err_rmdir[] = { 3739336Sdfr NFSERR_IO, 3749336Sdfr NFSERR_NOENT, 3759336Sdfr NFSERR_IO, 3769336Sdfr NFSERR_ACCES, 3779336Sdfr NFSERR_EXIST, 3789336Sdfr NFSERR_NOTDIR, 3799336Sdfr NFSERR_INVAL, 3809336Sdfr NFSERR_ROFS, 3819336Sdfr NFSERR_NAMETOL, 3829336Sdfr NFSERR_NOTEMPTY, 3839336Sdfr NFSERR_STALE, 3849336Sdfr NFSERR_BADHANDLE, 3859336Sdfr NFSERR_NOTSUPP, 3869336Sdfr NFSERR_SERVERFAULT, 3879336Sdfr 0, 3889336Sdfr}; 3899336Sdfr 3909336Sdfrstatic short nfsv3err_rename[] = { 3919336Sdfr NFSERR_IO, 3929336Sdfr NFSERR_NOENT, 3939336Sdfr NFSERR_IO, 3949336Sdfr NFSERR_ACCES, 3959336Sdfr NFSERR_EXIST, 3969336Sdfr NFSERR_XDEV, 3979336Sdfr NFSERR_NOTDIR, 3989336Sdfr NFSERR_ISDIR, 3999336Sdfr NFSERR_INVAL, 4009336Sdfr NFSERR_NOSPC, 4019336Sdfr NFSERR_ROFS, 4029336Sdfr NFSERR_MLINK, 4039336Sdfr NFSERR_NAMETOL, 4049336Sdfr NFSERR_NOTEMPTY, 4059336Sdfr NFSERR_DQUOT, 4069336Sdfr NFSERR_STALE, 4079336Sdfr NFSERR_BADHANDLE, 4089336Sdfr NFSERR_NOTSUPP, 4099336Sdfr NFSERR_SERVERFAULT, 4109336Sdfr 0, 4119336Sdfr}; 4129336Sdfr 4139336Sdfrstatic short nfsv3err_link[] = { 4149336Sdfr NFSERR_IO, 4159336Sdfr NFSERR_IO, 4169336Sdfr NFSERR_ACCES, 4179336Sdfr NFSERR_EXIST, 4189336Sdfr NFSERR_XDEV, 4199336Sdfr NFSERR_NOTDIR, 4209336Sdfr NFSERR_INVAL, 4219336Sdfr NFSERR_NOSPC, 4229336Sdfr NFSERR_ROFS, 4239336Sdfr NFSERR_MLINK, 4249336Sdfr NFSERR_NAMETOL, 4259336Sdfr NFSERR_DQUOT, 4269336Sdfr NFSERR_STALE, 4279336Sdfr NFSERR_BADHANDLE, 4289336Sdfr NFSERR_NOTSUPP, 4299336Sdfr NFSERR_SERVERFAULT, 4309336Sdfr 0, 4319336Sdfr}; 4329336Sdfr 4339336Sdfrstatic short nfsv3err_readdir[] = { 4349336Sdfr NFSERR_IO, 4359336Sdfr NFSERR_IO, 4369336Sdfr NFSERR_ACCES, 4379336Sdfr NFSERR_NOTDIR, 4389336Sdfr NFSERR_STALE, 4399336Sdfr NFSERR_BADHANDLE, 4409336Sdfr NFSERR_BAD_COOKIE, 4419336Sdfr NFSERR_TOOSMALL, 4429336Sdfr NFSERR_SERVERFAULT, 4439336Sdfr 0, 4449336Sdfr}; 4459336Sdfr 4469336Sdfrstatic short nfsv3err_readdirplus[] = { 4479336Sdfr NFSERR_IO, 4489336Sdfr NFSERR_IO, 4499336Sdfr NFSERR_ACCES, 4509336Sdfr NFSERR_NOTDIR, 4519336Sdfr NFSERR_STALE, 4529336Sdfr NFSERR_BADHANDLE, 4539336Sdfr NFSERR_BAD_COOKIE, 4549336Sdfr NFSERR_NOTSUPP, 4559336Sdfr NFSERR_TOOSMALL, 4569336Sdfr NFSERR_SERVERFAULT, 4579336Sdfr 0, 4589336Sdfr}; 4599336Sdfr 4609336Sdfrstatic short nfsv3err_fsstat[] = { 4619336Sdfr NFSERR_IO, 4629336Sdfr NFSERR_IO, 4639336Sdfr NFSERR_STALE, 4649336Sdfr NFSERR_BADHANDLE, 4659336Sdfr NFSERR_SERVERFAULT, 4669336Sdfr 0, 4679336Sdfr}; 4689336Sdfr 4699336Sdfrstatic short nfsv3err_fsinfo[] = { 4709336Sdfr NFSERR_STALE, 4719336Sdfr NFSERR_STALE, 4729336Sdfr NFSERR_BADHANDLE, 4739336Sdfr NFSERR_SERVERFAULT, 4749336Sdfr 0, 4759336Sdfr}; 4769336Sdfr 4779336Sdfrstatic short nfsv3err_pathconf[] = { 4789336Sdfr NFSERR_STALE, 4799336Sdfr NFSERR_STALE, 4809336Sdfr NFSERR_BADHANDLE, 4819336Sdfr NFSERR_SERVERFAULT, 4829336Sdfr 0, 4839336Sdfr}; 4849336Sdfr 4859336Sdfrstatic short nfsv3err_commit[] = { 4869336Sdfr NFSERR_IO, 4879336Sdfr NFSERR_IO, 4889336Sdfr NFSERR_STALE, 4899336Sdfr NFSERR_BADHANDLE, 4909336Sdfr NFSERR_SERVERFAULT, 4919336Sdfr 0, 4929336Sdfr}; 4939336Sdfr 4949336Sdfrstatic short *nfsrv_v3errmap[] = { 4959336Sdfr nfsv3err_null, 4969336Sdfr nfsv3err_getattr, 4979336Sdfr nfsv3err_setattr, 4989336Sdfr nfsv3err_lookup, 4999336Sdfr nfsv3err_access, 5009336Sdfr nfsv3err_readlink, 5019336Sdfr nfsv3err_read, 5029336Sdfr nfsv3err_write, 5039336Sdfr nfsv3err_create, 5049336Sdfr nfsv3err_mkdir, 5059336Sdfr nfsv3err_symlink, 5069336Sdfr nfsv3err_mknod, 5079336Sdfr nfsv3err_remove, 5089336Sdfr nfsv3err_rmdir, 5099336Sdfr nfsv3err_rename, 5109336Sdfr nfsv3err_link, 5119336Sdfr nfsv3err_readdir, 5129336Sdfr nfsv3err_readdirplus, 5139336Sdfr nfsv3err_fsstat, 5149336Sdfr nfsv3err_fsinfo, 5159336Sdfr nfsv3err_pathconf, 5169336Sdfr nfsv3err_commit, 5179336Sdfr}; 5189336Sdfr 5191541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 5201541Srgrimesextern struct nfsrtt nfsrtt; 5211541Srgrimesextern time_t nqnfsstarttime; 5221541Srgrimesextern int nqsrv_clockskew; 5231541Srgrimesextern int nqsrv_writeslack; 5241541Srgrimesextern int nqsrv_maxlease; 5259336Sdfrextern struct nfsstats nfsstats; 5269336Sdfrextern int nqnfs_piggy[NFS_NPROCS]; 5279336Sdfrextern nfstype nfsv2_type[9]; 5289336Sdfrextern nfstype nfsv3_type[9]; 5299336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl; 5309336Sdfrextern u_long nfsnodehash; 5311541Srgrimes 5322997Swollman#ifdef VFS_LKM 5332997Swollmanstruct getfh_args; 5342997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *); 5352997Swollmanstruct nfssvc_args; 5362997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 5372997Swollman#endif 5382997Swollman 5393664SphkLIST_HEAD(nfsnodehashhead, nfsnode); 5403664Sphk 5411541Srgrimes/* 5421541Srgrimes * Create the header for an rpc request packet 5431541Srgrimes * The hsiz is the size of the rest of the nfs request header. 5441541Srgrimes * (just used to decide if a cluster is a good idea) 5451541Srgrimes */ 5461541Srgrimesstruct mbuf * 5471541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp) 5481541Srgrimes struct vnode *vp; 5491541Srgrimes u_long procid; 5501541Srgrimes int hsiz; 5511541Srgrimes caddr_t *bposp; 5521541Srgrimes{ 5531541Srgrimes register struct mbuf *mb; 5541541Srgrimes register u_long *tl; 5551541Srgrimes register caddr_t bpos; 5561541Srgrimes struct mbuf *mb2; 5571541Srgrimes struct nfsmount *nmp; 5581541Srgrimes int nqflag; 5591541Srgrimes 5601541Srgrimes MGET(mb, M_WAIT, MT_DATA); 5611541Srgrimes if (hsiz >= MINCLSIZE) 5621541Srgrimes MCLGET(mb, M_WAIT); 5631541Srgrimes mb->m_len = 0; 5641541Srgrimes bpos = mtod(mb, caddr_t); 5658876Srgrimes 5661541Srgrimes /* 5671541Srgrimes * For NQNFS, add lease request. 5681541Srgrimes */ 5691541Srgrimes if (vp) { 5701541Srgrimes nmp = VFSTONFS(vp->v_mount); 5711541Srgrimes if (nmp->nm_flag & NFSMNT_NQNFS) { 5721541Srgrimes nqflag = NQNFS_NEEDLEASE(vp, procid); 5731541Srgrimes if (nqflag) { 5741541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 5751541Srgrimes *tl++ = txdr_unsigned(nqflag); 5761541Srgrimes *tl = txdr_unsigned(nmp->nm_leaseterm); 5771541Srgrimes } else { 5781541Srgrimes nfsm_build(tl, u_long *, NFSX_UNSIGNED); 5791541Srgrimes *tl = 0; 5801541Srgrimes } 5811541Srgrimes } 5821541Srgrimes } 5831541Srgrimes /* Finally, return values */ 5841541Srgrimes *bposp = bpos; 5851541Srgrimes return (mb); 5861541Srgrimes} 5871541Srgrimes 5881541Srgrimes/* 5891541Srgrimes * Build the RPC header and fill in the authorization info. 5901541Srgrimes * The authorization string argument is only used when the credentials 5911541Srgrimes * come from outside of the kernel. 5921541Srgrimes * Returns the head of the mbuf list. 5931541Srgrimes */ 5941541Srgrimesstruct mbuf * 5959336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 5969336Sdfr verf_str, mrest, mrest_len, mbp, xidp) 5971541Srgrimes register struct ucred *cr; 5989336Sdfr int nmflag; 5991541Srgrimes int procid; 6001541Srgrimes int auth_type; 6011541Srgrimes int auth_len; 6021541Srgrimes char *auth_str; 6039336Sdfr int verf_len; 6049336Sdfr char *verf_str; 6051541Srgrimes struct mbuf *mrest; 6061541Srgrimes int mrest_len; 6071541Srgrimes struct mbuf **mbp; 6081541Srgrimes u_long *xidp; 6091541Srgrimes{ 6101541Srgrimes register struct mbuf *mb; 6111541Srgrimes register u_long *tl; 6121541Srgrimes register caddr_t bpos; 6131541Srgrimes register int i; 6141541Srgrimes struct mbuf *mreq, *mb2; 6151541Srgrimes int siz, grpsiz, authsiz; 6161541Srgrimes 6171541Srgrimes authsiz = nfsm_rndup(auth_len); 6181541Srgrimes MGETHDR(mb, M_WAIT, MT_DATA); 6199336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 6201541Srgrimes MCLGET(mb, M_WAIT); 6219336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 6229336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 6231541Srgrimes } else { 6249336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 6251541Srgrimes } 6261541Srgrimes mb->m_len = 0; 6271541Srgrimes mreq = mb; 6281541Srgrimes bpos = mtod(mb, caddr_t); 6291541Srgrimes 6301541Srgrimes /* 6311541Srgrimes * First the RPC header. 6321541Srgrimes */ 6339336Sdfr nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED); 6341541Srgrimes if (++nfs_xid == 0) 6351541Srgrimes nfs_xid++; 6361541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 6371541Srgrimes *tl++ = rpc_call; 6381541Srgrimes *tl++ = rpc_vers; 6399336Sdfr if (nmflag & NFSMNT_NQNFS) { 6401541Srgrimes *tl++ = txdr_unsigned(NQNFS_PROG); 6419336Sdfr *tl++ = txdr_unsigned(NQNFS_VER3); 6421541Srgrimes } else { 6431541Srgrimes *tl++ = txdr_unsigned(NFS_PROG); 6449336Sdfr if (nmflag & NFSMNT_NFSV3) 6459336Sdfr *tl++ = txdr_unsigned(NFS_VER3); 6469336Sdfr else 6479336Sdfr *tl++ = txdr_unsigned(NFS_VER2); 6481541Srgrimes } 6499336Sdfr if (nmflag & NFSMNT_NFSV3) 6509336Sdfr *tl++ = txdr_unsigned(procid); 6519336Sdfr else 6529336Sdfr *tl++ = txdr_unsigned(nfsv2_procid[procid]); 6531541Srgrimes 6541541Srgrimes /* 6551541Srgrimes * And then the authorization cred. 6561541Srgrimes */ 6571541Srgrimes *tl++ = txdr_unsigned(auth_type); 6581541Srgrimes *tl = txdr_unsigned(authsiz); 6591541Srgrimes switch (auth_type) { 6601541Srgrimes case RPCAUTH_UNIX: 6611541Srgrimes nfsm_build(tl, u_long *, auth_len); 6621541Srgrimes *tl++ = 0; /* stamp ?? */ 6631541Srgrimes *tl++ = 0; /* NULL hostname */ 6641541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 6651541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 6661541Srgrimes grpsiz = (auth_len >> 2) - 5; 6671541Srgrimes *tl++ = txdr_unsigned(grpsiz); 6681541Srgrimes for (i = 1; i <= grpsiz; i++) 6691541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 6701541Srgrimes break; 6719336Sdfr case RPCAUTH_KERB4: 6721541Srgrimes siz = auth_len; 6731541Srgrimes while (siz > 0) { 6741541Srgrimes if (M_TRAILINGSPACE(mb) == 0) { 6751541Srgrimes MGET(mb2, M_WAIT, MT_DATA); 6761541Srgrimes if (siz >= MINCLSIZE) 6771541Srgrimes MCLGET(mb2, M_WAIT); 6781541Srgrimes mb->m_next = mb2; 6791541Srgrimes mb = mb2; 6801541Srgrimes mb->m_len = 0; 6811541Srgrimes bpos = mtod(mb, caddr_t); 6821541Srgrimes } 6831541Srgrimes i = min(siz, M_TRAILINGSPACE(mb)); 6841541Srgrimes bcopy(auth_str, bpos, i); 6851541Srgrimes mb->m_len += i; 6861541Srgrimes auth_str += i; 6871541Srgrimes bpos += i; 6881541Srgrimes siz -= i; 6891541Srgrimes } 6901541Srgrimes if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 6911541Srgrimes for (i = 0; i < siz; i++) 6921541Srgrimes *bpos++ = '\0'; 6931541Srgrimes mb->m_len += siz; 6941541Srgrimes } 6951541Srgrimes break; 6961541Srgrimes }; 6979336Sdfr 6989336Sdfr /* 6999336Sdfr * And the verifier... 7009336Sdfr */ 7019336Sdfr nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 7029336Sdfr if (verf_str) { 7039336Sdfr *tl++ = txdr_unsigned(RPCAUTH_KERB4); 7049336Sdfr *tl = txdr_unsigned(verf_len); 7059336Sdfr siz = verf_len; 7069336Sdfr while (siz > 0) { 7079336Sdfr if (M_TRAILINGSPACE(mb) == 0) { 7089336Sdfr MGET(mb2, M_WAIT, MT_DATA); 7099336Sdfr if (siz >= MINCLSIZE) 7109336Sdfr MCLGET(mb2, M_WAIT); 7119336Sdfr mb->m_next = mb2; 7129336Sdfr mb = mb2; 7139336Sdfr mb->m_len = 0; 7149336Sdfr bpos = mtod(mb, caddr_t); 7159336Sdfr } 7169336Sdfr i = min(siz, M_TRAILINGSPACE(mb)); 7179336Sdfr bcopy(verf_str, bpos, i); 7189336Sdfr mb->m_len += i; 7199336Sdfr verf_str += i; 7209336Sdfr bpos += i; 7219336Sdfr siz -= i; 7229336Sdfr } 7239336Sdfr if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 7249336Sdfr for (i = 0; i < siz; i++) 7259336Sdfr *bpos++ = '\0'; 7269336Sdfr mb->m_len += siz; 7279336Sdfr } 7289336Sdfr } else { 7299336Sdfr *tl++ = txdr_unsigned(RPCAUTH_NULL); 7309336Sdfr *tl = 0; 7319336Sdfr } 7321541Srgrimes mb->m_next = mrest; 7339336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 7341541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 7351541Srgrimes *mbp = mb; 7361541Srgrimes return (mreq); 7371541Srgrimes} 7381541Srgrimes 7391541Srgrimes/* 7401541Srgrimes * copies mbuf chain to the uio scatter/gather list 7411541Srgrimes */ 7421549Srgrimesint 7431541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos) 7441541Srgrimes struct mbuf **mrep; 7451541Srgrimes register struct uio *uiop; 7461541Srgrimes int siz; 7471541Srgrimes caddr_t *dpos; 7481541Srgrimes{ 7491541Srgrimes register char *mbufcp, *uiocp; 7501541Srgrimes register int xfer, left, len; 7511541Srgrimes register struct mbuf *mp; 7521541Srgrimes long uiosiz, rem; 7531541Srgrimes int error = 0; 7541541Srgrimes 7551541Srgrimes mp = *mrep; 7561541Srgrimes mbufcp = *dpos; 7571541Srgrimes len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 7581541Srgrimes rem = nfsm_rndup(siz)-siz; 7591541Srgrimes while (siz > 0) { 7601541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 7611541Srgrimes return (EFBIG); 7621541Srgrimes left = uiop->uio_iov->iov_len; 7631541Srgrimes uiocp = uiop->uio_iov->iov_base; 7641541Srgrimes if (left > siz) 7651541Srgrimes left = siz; 7661541Srgrimes uiosiz = left; 7671541Srgrimes while (left > 0) { 7681541Srgrimes while (len == 0) { 7691541Srgrimes mp = mp->m_next; 7701541Srgrimes if (mp == NULL) 7711541Srgrimes return (EBADRPC); 7721541Srgrimes mbufcp = mtod(mp, caddr_t); 7731541Srgrimes len = mp->m_len; 7741541Srgrimes } 7751541Srgrimes xfer = (left > len) ? len : left; 7761541Srgrimes#ifdef notdef 7771541Srgrimes /* Not Yet.. */ 7781541Srgrimes if (uiop->uio_iov->iov_op != NULL) 7791541Srgrimes (*(uiop->uio_iov->iov_op)) 7801541Srgrimes (mbufcp, uiocp, xfer); 7811541Srgrimes else 7821541Srgrimes#endif 7831541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 7841541Srgrimes bcopy(mbufcp, uiocp, xfer); 7851541Srgrimes else 7861541Srgrimes copyout(mbufcp, uiocp, xfer); 7871541Srgrimes left -= xfer; 7881541Srgrimes len -= xfer; 7891541Srgrimes mbufcp += xfer; 7901541Srgrimes uiocp += xfer; 7911541Srgrimes uiop->uio_offset += xfer; 7921541Srgrimes uiop->uio_resid -= xfer; 7931541Srgrimes } 7941541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 7951541Srgrimes uiop->uio_iovcnt--; 7961541Srgrimes uiop->uio_iov++; 7971541Srgrimes } else { 7981541Srgrimes uiop->uio_iov->iov_base += uiosiz; 7991541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 8001541Srgrimes } 8011541Srgrimes siz -= uiosiz; 8021541Srgrimes } 8031541Srgrimes *dpos = mbufcp; 8041541Srgrimes *mrep = mp; 8051541Srgrimes if (rem > 0) { 8061541Srgrimes if (len < rem) 8071541Srgrimes error = nfs_adv(mrep, dpos, rem, len); 8081541Srgrimes else 8091541Srgrimes *dpos += rem; 8101541Srgrimes } 8111541Srgrimes return (error); 8121541Srgrimes} 8131541Srgrimes 8141541Srgrimes/* 8151541Srgrimes * copies a uio scatter/gather list to an mbuf chain... 8161541Srgrimes */ 8171549Srgrimesint 8181541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos) 8191541Srgrimes register struct uio *uiop; 8201541Srgrimes struct mbuf **mq; 8211541Srgrimes int siz; 8221541Srgrimes caddr_t *bpos; 8231541Srgrimes{ 8241541Srgrimes register char *uiocp; 8251541Srgrimes register struct mbuf *mp, *mp2; 8261541Srgrimes register int xfer, left, mlen; 8271541Srgrimes int uiosiz, clflg, rem; 8281541Srgrimes char *cp; 8291541Srgrimes 8301541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 8311541Srgrimes clflg = 1; 8321541Srgrimes else 8331541Srgrimes clflg = 0; 8341541Srgrimes rem = nfsm_rndup(siz)-siz; 8351541Srgrimes mp = mp2 = *mq; 8361541Srgrimes while (siz > 0) { 8371541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 8381541Srgrimes return (EINVAL); 8391541Srgrimes left = uiop->uio_iov->iov_len; 8401541Srgrimes uiocp = uiop->uio_iov->iov_base; 8411541Srgrimes if (left > siz) 8421541Srgrimes left = siz; 8431541Srgrimes uiosiz = left; 8441541Srgrimes while (left > 0) { 8451541Srgrimes mlen = M_TRAILINGSPACE(mp); 8461541Srgrimes if (mlen == 0) { 8471541Srgrimes MGET(mp, M_WAIT, MT_DATA); 8481541Srgrimes if (clflg) 8491541Srgrimes MCLGET(mp, M_WAIT); 8501541Srgrimes mp->m_len = 0; 8511541Srgrimes mp2->m_next = mp; 8521541Srgrimes mp2 = mp; 8531541Srgrimes mlen = M_TRAILINGSPACE(mp); 8541541Srgrimes } 8551541Srgrimes xfer = (left > mlen) ? mlen : left; 8561541Srgrimes#ifdef notdef 8571541Srgrimes /* Not Yet.. */ 8581541Srgrimes if (uiop->uio_iov->iov_op != NULL) 8591541Srgrimes (*(uiop->uio_iov->iov_op)) 8601541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 8611541Srgrimes else 8621541Srgrimes#endif 8631541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 8641541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 8651541Srgrimes else 8661541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 8671541Srgrimes mp->m_len += xfer; 8681541Srgrimes left -= xfer; 8691541Srgrimes uiocp += xfer; 8701541Srgrimes uiop->uio_offset += xfer; 8711541Srgrimes uiop->uio_resid -= xfer; 8721541Srgrimes } 8731541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 8741541Srgrimes uiop->uio_iovcnt--; 8751541Srgrimes uiop->uio_iov++; 8761541Srgrimes } else { 8771541Srgrimes uiop->uio_iov->iov_base += uiosiz; 8781541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 8791541Srgrimes } 8801541Srgrimes siz -= uiosiz; 8811541Srgrimes } 8821541Srgrimes if (rem > 0) { 8831541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 8841541Srgrimes MGET(mp, M_WAIT, MT_DATA); 8851541Srgrimes mp->m_len = 0; 8861541Srgrimes mp2->m_next = mp; 8871541Srgrimes } 8881541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 8891541Srgrimes for (left = 0; left < rem; left++) 8901541Srgrimes *cp++ = '\0'; 8911541Srgrimes mp->m_len += rem; 8921541Srgrimes *bpos = cp; 8931541Srgrimes } else 8941541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 8951541Srgrimes *mq = mp; 8961541Srgrimes return (0); 8971541Srgrimes} 8981541Srgrimes 8991541Srgrimes/* 9001541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous 9011541Srgrimes * pointed to by returned val. 9021541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 9031541Srgrimes * cases. (The macros use the vars. dpos and dpos2) 9041541Srgrimes */ 9051549Srgrimesint 9061541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2) 9071541Srgrimes struct mbuf **mdp; 9081541Srgrimes caddr_t *dposp; 9091541Srgrimes int siz; 9101541Srgrimes int left; 9111541Srgrimes caddr_t *cp2; 9121541Srgrimes{ 9131541Srgrimes register struct mbuf *mp, *mp2; 9141541Srgrimes register int siz2, xfer; 9151541Srgrimes register caddr_t p; 9161541Srgrimes 9171541Srgrimes mp = *mdp; 9181541Srgrimes while (left == 0) { 9191541Srgrimes *mdp = mp = mp->m_next; 9201541Srgrimes if (mp == NULL) 9211541Srgrimes return (EBADRPC); 9221541Srgrimes left = mp->m_len; 9231541Srgrimes *dposp = mtod(mp, caddr_t); 9241541Srgrimes } 9251541Srgrimes if (left >= siz) { 9261541Srgrimes *cp2 = *dposp; 9271541Srgrimes *dposp += siz; 9281541Srgrimes } else if (mp->m_next == NULL) { 9291541Srgrimes return (EBADRPC); 9301541Srgrimes } else if (siz > MHLEN) { 9311541Srgrimes panic("nfs S too big"); 9321541Srgrimes } else { 9331541Srgrimes MGET(mp2, M_WAIT, MT_DATA); 9341541Srgrimes mp2->m_next = mp->m_next; 9351541Srgrimes mp->m_next = mp2; 9361541Srgrimes mp->m_len -= left; 9371541Srgrimes mp = mp2; 9381541Srgrimes *cp2 = p = mtod(mp, caddr_t); 9391541Srgrimes bcopy(*dposp, p, left); /* Copy what was left */ 9401541Srgrimes siz2 = siz-left; 9411541Srgrimes p += left; 9421541Srgrimes mp2 = mp->m_next; 9431541Srgrimes /* Loop around copying up the siz2 bytes */ 9441541Srgrimes while (siz2 > 0) { 9451541Srgrimes if (mp2 == NULL) 9461541Srgrimes return (EBADRPC); 9471541Srgrimes xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 9481541Srgrimes if (xfer > 0) { 9491541Srgrimes bcopy(mtod(mp2, caddr_t), p, xfer); 9501541Srgrimes NFSMADV(mp2, xfer); 9511541Srgrimes mp2->m_len -= xfer; 9521541Srgrimes p += xfer; 9531541Srgrimes siz2 -= xfer; 9541541Srgrimes } 9551541Srgrimes if (siz2 > 0) 9561541Srgrimes mp2 = mp2->m_next; 9571541Srgrimes } 9581541Srgrimes mp->m_len = siz; 9591541Srgrimes *mdp = mp2; 9601541Srgrimes *dposp = mtod(mp2, caddr_t); 9611541Srgrimes } 9621541Srgrimes return (0); 9631541Srgrimes} 9641541Srgrimes 9651541Srgrimes/* 9661541Srgrimes * Advance the position in the mbuf chain. 9671541Srgrimes */ 9681549Srgrimesint 9691541Srgrimesnfs_adv(mdp, dposp, offs, left) 9701541Srgrimes struct mbuf **mdp; 9711541Srgrimes caddr_t *dposp; 9721541Srgrimes int offs; 9731541Srgrimes int left; 9741541Srgrimes{ 9751541Srgrimes register struct mbuf *m; 9761541Srgrimes register int s; 9771541Srgrimes 9781541Srgrimes m = *mdp; 9791541Srgrimes s = left; 9801541Srgrimes while (s < offs) { 9811541Srgrimes offs -= s; 9821541Srgrimes m = m->m_next; 9831541Srgrimes if (m == NULL) 9841541Srgrimes return (EBADRPC); 9851541Srgrimes s = m->m_len; 9861541Srgrimes } 9871541Srgrimes *mdp = m; 9881541Srgrimes *dposp = mtod(m, caddr_t)+offs; 9891541Srgrimes return (0); 9901541Srgrimes} 9911541Srgrimes 9921541Srgrimes/* 9931541Srgrimes * Copy a string into mbufs for the hard cases... 9941541Srgrimes */ 9951549Srgrimesint 9961541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz) 9971541Srgrimes struct mbuf **mb; 9981541Srgrimes char **bpos; 9991541Srgrimes char *cp; 10001541Srgrimes long siz; 10011541Srgrimes{ 10021549Srgrimes register struct mbuf *m1 = 0, *m2; 10031541Srgrimes long left, xfer, len, tlen; 10041541Srgrimes u_long *tl; 10051541Srgrimes int putsize; 10061541Srgrimes 10071541Srgrimes putsize = 1; 10081541Srgrimes m2 = *mb; 10091541Srgrimes left = M_TRAILINGSPACE(m2); 10101541Srgrimes if (left > 0) { 10111541Srgrimes tl = ((u_long *)(*bpos)); 10121541Srgrimes *tl++ = txdr_unsigned(siz); 10131541Srgrimes putsize = 0; 10141541Srgrimes left -= NFSX_UNSIGNED; 10151541Srgrimes m2->m_len += NFSX_UNSIGNED; 10161541Srgrimes if (left > 0) { 10171541Srgrimes bcopy(cp, (caddr_t) tl, left); 10181541Srgrimes siz -= left; 10191541Srgrimes cp += left; 10201541Srgrimes m2->m_len += left; 10211541Srgrimes left = 0; 10221541Srgrimes } 10231541Srgrimes } 10241541Srgrimes /* Loop around adding mbufs */ 10251541Srgrimes while (siz > 0) { 10261541Srgrimes MGET(m1, M_WAIT, MT_DATA); 10271541Srgrimes if (siz > MLEN) 10281541Srgrimes MCLGET(m1, M_WAIT); 10291541Srgrimes m1->m_len = NFSMSIZ(m1); 10301541Srgrimes m2->m_next = m1; 10311541Srgrimes m2 = m1; 10321541Srgrimes tl = mtod(m1, u_long *); 10331541Srgrimes tlen = 0; 10341541Srgrimes if (putsize) { 10351541Srgrimes *tl++ = txdr_unsigned(siz); 10361541Srgrimes m1->m_len -= NFSX_UNSIGNED; 10371541Srgrimes tlen = NFSX_UNSIGNED; 10381541Srgrimes putsize = 0; 10391541Srgrimes } 10401541Srgrimes if (siz < m1->m_len) { 10411541Srgrimes len = nfsm_rndup(siz); 10421541Srgrimes xfer = siz; 10431541Srgrimes if (xfer < len) 10441541Srgrimes *(tl+(xfer>>2)) = 0; 10451541Srgrimes } else { 10461541Srgrimes xfer = len = m1->m_len; 10471541Srgrimes } 10481541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 10491541Srgrimes m1->m_len = len+tlen; 10501541Srgrimes siz -= xfer; 10511541Srgrimes cp += xfer; 10521541Srgrimes } 10531541Srgrimes *mb = m1; 10541541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 10551541Srgrimes return (0); 10561541Srgrimes} 10571541Srgrimes 10581541Srgrimes/* 10591541Srgrimes * Called once to initialize data structures... 10601541Srgrimes */ 10611549Srgrimesint 10621541Srgrimesnfs_init() 10631541Srgrimes{ 10641541Srgrimes register int i; 10651541Srgrimes 10669336Sdfr /* 10679336Sdfr * Check to see if major data structures haven't bloated. 10689336Sdfr */ 10699336Sdfr if (sizeof (struct nfsnode) > NFS_NODEALLOC) { 10709336Sdfr printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); 10719336Sdfr printf("Try reducing NFS_SMALLFH\n"); 10729336Sdfr } 10739336Sdfr if (sizeof (struct nfsmount) > NFS_MNTALLOC) { 10749336Sdfr printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); 10759336Sdfr printf("Try reducing NFS_MUIDHASHSIZ\n"); 10769336Sdfr } 10779336Sdfr if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 10789336Sdfr printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 10799336Sdfr printf("Try reducing NFS_UIDHASHSIZ\n"); 10809336Sdfr } 10819336Sdfr if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 10829336Sdfr printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 10839336Sdfr printf("Try unionizing the nu_nickname and nu_flag fields\n"); 10849336Sdfr } 10851541Srgrimes nfsrtt.pos = 0; 10861541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 10871541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 10881541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 10891541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 10901541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 10911541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 10921541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 10931541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 10949336Sdfr rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 10951541Srgrimes nfs_prog = txdr_unsigned(NFS_PROG); 10969336Sdfr nqnfs_prog = txdr_unsigned(NQNFS_PROG); 10971541Srgrimes nfs_true = txdr_unsigned(TRUE); 10981541Srgrimes nfs_false = txdr_unsigned(FALSE); 10993664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 11009336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 11019336Sdfr if (nfs_ticks < 1) 11029336Sdfr nfs_ticks = 1; 11031541Srgrimes /* Ensure async daemons disabled */ 11041541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 11051541Srgrimes nfs_iodwant[i] = (struct proc *)0; 11061541Srgrimes TAILQ_INIT(&nfs_bufq); 11071541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 11081541Srgrimes nfsrv_init(0); /* Init server data structures */ 11091541Srgrimes nfsrv_initcache(); /* Init the server request cache */ 11101541Srgrimes 11111541Srgrimes /* 11121541Srgrimes * Initialize the nqnfs server stuff. 11131541Srgrimes */ 11141541Srgrimes if (nqnfsstarttime == 0) { 11151541Srgrimes nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 11161541Srgrimes + nqsrv_clockskew + nqsrv_writeslack; 11171541Srgrimes NQLOADNOVRAM(nqnfsstarttime); 11183664Sphk CIRCLEQ_INIT(&nqtimerhead); 11193664Sphk nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 11201541Srgrimes } 11211541Srgrimes 11221541Srgrimes /* 11231541Srgrimes * Initialize reply list and start timer 11241541Srgrimes */ 11253664Sphk TAILQ_INIT(&nfs_reqq); 11263305Sphk nfs_timer(0); 11271549Srgrimes 11289336Sdfr#ifdef __FreeBSD__ 11292997Swollman /* 11302997Swollman * Set up lease_check and lease_updatetime so that other parts 11312997Swollman * of the system can call us, if we are loadable. 11322997Swollman */ 11332997Swollman lease_check = nfs_lease_check; 11342997Swollman lease_updatetime = nfs_lease_updatetime; 11352997Swollman vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ 11362997Swollman#ifdef VFS_LKM 11372997Swollman sysent[SYS_nfssvc].sy_narg = 2; 11382997Swollman sysent[SYS_nfssvc].sy_call = nfssvc; 11392997Swollman sysent[SYS_getfh].sy_narg = 2; 11402997Swollman sysent[SYS_getfh].sy_call = getfh; 11412997Swollman#endif 11429336Sdfr#endif 11432997Swollman 11441549Srgrimes return (0); 11451541Srgrimes} 11461541Srgrimes 11471541Srgrimes/* 11481541Srgrimes * Attribute cache routines. 11491541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 11501541Srgrimes * that are on the mbuf list 11511541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 11521541Srgrimes * error otherwise 11531541Srgrimes */ 11541541Srgrimes 11551541Srgrimes/* 11561541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 11571541Srgrimes * the values on the mbuf list and 11581541Srgrimes * Iff vap not NULL 11591541Srgrimes * copy the attributes to *vaper 11601541Srgrimes */ 11611549Srgrimesint 11621541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper) 11631541Srgrimes struct vnode **vpp; 11641541Srgrimes struct mbuf **mdp; 11651541Srgrimes caddr_t *dposp; 11661541Srgrimes struct vattr *vaper; 11671541Srgrimes{ 11681541Srgrimes register struct vnode *vp = *vpp; 11691541Srgrimes register struct vattr *vap; 11709336Sdfr register struct nfs_fattr *fp; 11713664Sphk register struct nfsnode *np; 11723664Sphk register struct nfsnodehashhead *nhpp; 11731541Srgrimes register long t1; 11749336Sdfr caddr_t cp2; 11759336Sdfr int error = 0, rdev; 11761541Srgrimes struct mbuf *md; 11771541Srgrimes enum vtype vtyp; 11781541Srgrimes u_short vmode; 11791541Srgrimes struct timespec mtime; 11801541Srgrimes struct vnode *nvp; 11819336Sdfr quad_t tval; 11829336Sdfr int v3 = NFS_ISV3(vp); 11831541Srgrimes 11841541Srgrimes md = *mdp; 11859336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 11869336Sdfr if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) 11871541Srgrimes return (error); 11889336Sdfr fp = (struct nfs_fattr *)cp2; 11899336Sdfr if (v3) { 11909336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 11919336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 11929336Sdfr rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 11939336Sdfr fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 11949336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 11951541Srgrimes } else { 11969336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 11979336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 11989336Sdfr /* 11999336Sdfr * XXX 12009336Sdfr * 12019336Sdfr * The duplicate information returned in fa_type and fa_mode 12029336Sdfr * is an ambiguity in the NFS version 2 protocol. 12039336Sdfr * 12049336Sdfr * VREG should be taken literally as a regular file. If a 12059336Sdfr * server intents to return some type information differently 12069336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 12079336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 12089336Sdfr * leave the examination of the mode bits even in the VREG 12099336Sdfr * case to avoid breakage for bogus servers, but we make sure 12109336Sdfr * that there are actually type bits set in the upper part of 12119336Sdfr * fa_mode (and failing that, trust the va_type field). 12129336Sdfr * 12139336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 12149336Sdfr * contain any type information (while also introduing sockets 12159336Sdfr * and FIFOs for fa_type). 12169336Sdfr */ 12179336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 12189336Sdfr vtyp = IFTOVT(vmode); 12199336Sdfr rdev = fxdr_unsigned(long, fp->fa2_rdev); 12209336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 12219336Sdfr 12229336Sdfr /* 12239336Sdfr * Really ugly NFSv2 kludge. 12249336Sdfr */ 12259336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 12269336Sdfr vtyp = VFIFO; 12271541Srgrimes } 12289336Sdfr 12291541Srgrimes /* 12301541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 12318876Srgrimes * n_mtime fields. Check to see if it represents a special 12321541Srgrimes * device, and if so, check for a possible alias. Once the 12331541Srgrimes * correct vnode has been obtained, fill in the rest of the 12341541Srgrimes * information. 12351541Srgrimes */ 12361541Srgrimes np = VTONFS(vp); 12371541Srgrimes if (vp->v_type == VNON) { 12389336Sdfr /* 12399336Sdfr * If we had a lock and it turns out that the vnode 12409336Sdfr * is an object which we don't want to lock (e.g. VDIR) 12419336Sdfr * to avoid nasty hanging problems on a server crash, 12429336Sdfr * then release it here. 12439336Sdfr */ 12449336Sdfr if (vtyp != VREG && VOP_ISLOCKED(vp)) 12459336Sdfr VOP_UNLOCK(vp); 12469336Sdfr vp->v_type = vtyp; 12471541Srgrimes if (vp->v_type == VFIFO) { 12481541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 12491541Srgrimes } 12501541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 12511541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 12523305Sphk nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 12533305Sphk if (nvp) { 12541541Srgrimes /* 12551541Srgrimes * Discard unneeded vnode, but save its nfsnode. 12561541Srgrimes */ 12573664Sphk LIST_REMOVE(np, n_hash); 12581541Srgrimes nvp->v_data = vp->v_data; 12591541Srgrimes vp->v_data = NULL; 12601541Srgrimes vp->v_op = spec_vnodeop_p; 12611541Srgrimes vrele(vp); 12621541Srgrimes vgone(vp); 12631541Srgrimes /* 12641541Srgrimes * Reinitialize aliased node. 12651541Srgrimes */ 12661541Srgrimes np->n_vnode = nvp; 12679336Sdfr nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize)); 12683664Sphk LIST_INSERT_HEAD(nhpp, np, n_hash); 12691541Srgrimes *vpp = vp = nvp; 12701541Srgrimes } 12711541Srgrimes } 12721541Srgrimes np->n_mtime = mtime.ts_sec; 12731541Srgrimes } 12741541Srgrimes vap = &np->n_vattr; 12751541Srgrimes vap->va_type = vtyp; 12761541Srgrimes vap->va_mode = (vmode & 07777); 12771541Srgrimes vap->va_rdev = (dev_t)rdev; 12781541Srgrimes vap->va_mtime = mtime; 12791541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 12809336Sdfr if (v3) { 12819336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 12829336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 12839336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 12849336Sdfr fxdr_hyper(&fp->fa3_size, &vap->va_size); 12859336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 12869336Sdfr fxdr_hyper(&fp->fa3_used, &vap->va_bytes); 12879336Sdfr vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]); 12889336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 12899336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 12909336Sdfr vap->va_flags = 0; 12919336Sdfr vap->va_filerev = 0; 12921541Srgrimes } else { 12939336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 12949336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 12959336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 12969336Sdfr vap->va_size = fxdr_unsigned(u_long, fp->fa2_size); 12979336Sdfr vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize); 12989336Sdfr vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE; 12999336Sdfr vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid); 13009336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 13011541Srgrimes vap->va_flags = 0; 13029336Sdfr vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec); 13039336Sdfr vap->va_ctime.ts_nsec = 0; 13049336Sdfr vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec); 13051541Srgrimes vap->va_filerev = 0; 13061541Srgrimes } 13071541Srgrimes if (vap->va_size != np->n_size) { 13081541Srgrimes if (vap->va_type == VREG) { 13091541Srgrimes if (np->n_flag & NMODIFIED) { 13101541Srgrimes if (vap->va_size < np->n_size) 13111541Srgrimes vap->va_size = np->n_size; 13121541Srgrimes else 13131541Srgrimes np->n_size = vap->va_size; 13141541Srgrimes } else 13151541Srgrimes np->n_size = vap->va_size; 13161541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 13171541Srgrimes } else 13181541Srgrimes np->n_size = vap->va_size; 13191541Srgrimes } 13201541Srgrimes np->n_attrstamp = time.tv_sec; 13211541Srgrimes if (vaper != NULL) { 13221541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 13231541Srgrimes if (np->n_flag & NCHG) { 13249336Sdfr if (np->n_flag & NACC) 13259336Sdfr vaper->va_atime = np->n_atim; 13269336Sdfr if (np->n_flag & NUPD) 13279336Sdfr vaper->va_mtime = np->n_mtim; 13281541Srgrimes } 13291541Srgrimes } 13301541Srgrimes return (0); 13311541Srgrimes} 13321541Srgrimes 13331541Srgrimes/* 13341541Srgrimes * Check the time stamp 13351541Srgrimes * If the cache is valid, copy contents to *vap and return 0 13361541Srgrimes * otherwise return an error 13371541Srgrimes */ 13381549Srgrimesint 13391541Srgrimesnfs_getattrcache(vp, vaper) 13401541Srgrimes register struct vnode *vp; 13411541Srgrimes struct vattr *vaper; 13421541Srgrimes{ 13431541Srgrimes register struct nfsnode *np = VTONFS(vp); 13441541Srgrimes register struct vattr *vap; 13451541Srgrimes 13469336Sdfr if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 13471541Srgrimes nfsstats.attrcache_misses++; 13481541Srgrimes return (ENOENT); 13491541Srgrimes } 13501541Srgrimes nfsstats.attrcache_hits++; 13511541Srgrimes vap = &np->n_vattr; 13521541Srgrimes if (vap->va_size != np->n_size) { 13531541Srgrimes if (vap->va_type == VREG) { 13541541Srgrimes if (np->n_flag & NMODIFIED) { 13551541Srgrimes if (vap->va_size < np->n_size) 13561541Srgrimes vap->va_size = np->n_size; 13571541Srgrimes else 13581541Srgrimes np->n_size = vap->va_size; 13591541Srgrimes } else 13601541Srgrimes np->n_size = vap->va_size; 13611541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 13621541Srgrimes } else 13631541Srgrimes np->n_size = vap->va_size; 13641541Srgrimes } 13651541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 13661541Srgrimes if (np->n_flag & NCHG) { 13679336Sdfr if (np->n_flag & NACC) 13689336Sdfr vaper->va_atime = np->n_atim; 13699336Sdfr if (np->n_flag & NUPD) 13709336Sdfr vaper->va_mtime = np->n_mtim; 13711541Srgrimes } 13721541Srgrimes return (0); 13731541Srgrimes} 13741541Srgrimes 13751541Srgrimes/* 13761541Srgrimes * Set up nameidata for a lookup() call and do it 13771541Srgrimes */ 13781549Srgrimesint 13799336Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) 13801541Srgrimes register struct nameidata *ndp; 13811541Srgrimes fhandle_t *fhp; 13821541Srgrimes int len; 13831541Srgrimes struct nfssvc_sock *slp; 13841541Srgrimes struct mbuf *nam; 13851541Srgrimes struct mbuf **mdp; 13861541Srgrimes caddr_t *dposp; 13879336Sdfr struct vnode **retdirp; 13881541Srgrimes struct proc *p; 13899336Sdfr int kerbflag; 13901541Srgrimes{ 13911541Srgrimes register int i, rem; 13921541Srgrimes register struct mbuf *md; 13931541Srgrimes register char *fromcp, *tocp; 13941541Srgrimes struct vnode *dp; 13951541Srgrimes int error, rdonly; 13961541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 13971541Srgrimes 13989336Sdfr *retdirp = (struct vnode *)0; 13991541Srgrimes MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 14001541Srgrimes /* 14011541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 14021541Srgrimes * and set the various ndp fields appropriately. 14031541Srgrimes */ 14041541Srgrimes fromcp = *dposp; 14051541Srgrimes tocp = cnp->cn_pnbuf; 14061541Srgrimes md = *mdp; 14071541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 14081541Srgrimes cnp->cn_hash = 0; 14091541Srgrimes for (i = 0; i < len; i++) { 14101541Srgrimes while (rem == 0) { 14111541Srgrimes md = md->m_next; 14121541Srgrimes if (md == NULL) { 14131541Srgrimes error = EBADRPC; 14141541Srgrimes goto out; 14151541Srgrimes } 14161541Srgrimes fromcp = mtod(md, caddr_t); 14171541Srgrimes rem = md->m_len; 14181541Srgrimes } 14191541Srgrimes if (*fromcp == '\0' || *fromcp == '/') { 14209336Sdfr error = EACCES; 14211541Srgrimes goto out; 14221541Srgrimes } 14231541Srgrimes cnp->cn_hash += (unsigned char)*fromcp; 14241541Srgrimes *tocp++ = *fromcp++; 14251541Srgrimes rem--; 14261541Srgrimes } 14271541Srgrimes *tocp = '\0'; 14281541Srgrimes *mdp = md; 14291541Srgrimes *dposp = fromcp; 14301541Srgrimes len = nfsm_rndup(len)-len; 14311541Srgrimes if (len > 0) { 14321541Srgrimes if (rem >= len) 14331541Srgrimes *dposp += len; 14349336Sdfr else if (error = nfs_adv(mdp, dposp, len, rem)) 14359336Sdfr goto out; 14361541Srgrimes } 14371541Srgrimes ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 14381541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 14391541Srgrimes /* 14401541Srgrimes * Extract and set starting directory. 14411541Srgrimes */ 14429336Sdfr if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 14439336Sdfr nam, &rdonly, kerbflag)) 14441541Srgrimes goto out; 14451541Srgrimes if (dp->v_type != VDIR) { 14466417Sdg nfsrv_vrele(dp); 14471541Srgrimes error = ENOTDIR; 14481541Srgrimes goto out; 14491541Srgrimes } 14509336Sdfr VREF(dp); 14519336Sdfr *retdirp = dp; 14521541Srgrimes ndp->ni_startdir = dp; 14531541Srgrimes if (rdonly) 14541541Srgrimes cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 14551541Srgrimes else 14561541Srgrimes cnp->cn_flags |= NOCROSSMOUNT; 14571541Srgrimes /* 14581541Srgrimes * And call lookup() to do the real work 14591541Srgrimes */ 14601541Srgrimes cnp->cn_proc = p; 14619336Sdfr if (error = lookup(ndp)) 14621541Srgrimes goto out; 14631541Srgrimes /* 14641541Srgrimes * Check for encountering a symbolic link 14651541Srgrimes */ 14661541Srgrimes if (cnp->cn_flags & ISSYMLINK) { 14671541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 14681541Srgrimes vput(ndp->ni_dvp); 14691541Srgrimes else 14701541Srgrimes vrele(ndp->ni_dvp); 14711541Srgrimes vput(ndp->ni_vp); 14721541Srgrimes ndp->ni_vp = NULL; 14731541Srgrimes error = EINVAL; 14741541Srgrimes goto out; 14751541Srgrimes } 14768832Sdg 14778832Sdg nfsrv_vmio(ndp->ni_vp); 14788832Sdg 14791541Srgrimes /* 14801541Srgrimes * Check for saved name request 14811541Srgrimes */ 14821541Srgrimes if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 14831541Srgrimes cnp->cn_flags |= HASBUF; 14841541Srgrimes return (0); 14851541Srgrimes } 14861541Srgrimesout: 14871541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 14881541Srgrimes return (error); 14891541Srgrimes} 14901541Srgrimes 14911541Srgrimes/* 14921541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 14931541Srgrimes * boundary and only trims off the back end 14941541Srgrimes */ 14951541Srgrimesvoid 14961541Srgrimesnfsm_adj(mp, len, nul) 14971541Srgrimes struct mbuf *mp; 14981541Srgrimes register int len; 14991541Srgrimes int nul; 15001541Srgrimes{ 15011541Srgrimes register struct mbuf *m; 15021541Srgrimes register int count, i; 15031541Srgrimes register char *cp; 15041541Srgrimes 15051541Srgrimes /* 15061541Srgrimes * Trim from tail. Scan the mbuf chain, 15071541Srgrimes * calculating its length and finding the last mbuf. 15081541Srgrimes * If the adjustment only affects this mbuf, then just 15091541Srgrimes * adjust and return. Otherwise, rescan and truncate 15101541Srgrimes * after the remaining size. 15111541Srgrimes */ 15121541Srgrimes count = 0; 15131541Srgrimes m = mp; 15141541Srgrimes for (;;) { 15151541Srgrimes count += m->m_len; 15161541Srgrimes if (m->m_next == (struct mbuf *)0) 15171541Srgrimes break; 15181541Srgrimes m = m->m_next; 15191541Srgrimes } 15201541Srgrimes if (m->m_len > len) { 15211541Srgrimes m->m_len -= len; 15221541Srgrimes if (nul > 0) { 15231541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 15241541Srgrimes for (i = 0; i < nul; i++) 15251541Srgrimes *cp++ = '\0'; 15261541Srgrimes } 15271541Srgrimes return; 15281541Srgrimes } 15291541Srgrimes count -= len; 15301541Srgrimes if (count < 0) 15311541Srgrimes count = 0; 15321541Srgrimes /* 15331541Srgrimes * Correct length for chain is "count". 15341541Srgrimes * Find the mbuf with last data, adjust its length, 15351541Srgrimes * and toss data from remaining mbufs on chain. 15361541Srgrimes */ 15371541Srgrimes for (m = mp; m; m = m->m_next) { 15381541Srgrimes if (m->m_len >= count) { 15391541Srgrimes m->m_len = count; 15401541Srgrimes if (nul > 0) { 15411541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 15421541Srgrimes for (i = 0; i < nul; i++) 15431541Srgrimes *cp++ = '\0'; 15441541Srgrimes } 15451541Srgrimes break; 15461541Srgrimes } 15471541Srgrimes count -= m->m_len; 15481541Srgrimes } 15493305Sphk for (m = m->m_next;m;m = m->m_next) 15501541Srgrimes m->m_len = 0; 15511541Srgrimes} 15521541Srgrimes 15531541Srgrimes/* 15549336Sdfr * Make these functions instead of macros, so that the kernel text size 15559336Sdfr * doesn't get too big... 15569336Sdfr */ 15579336Sdfrvoid 15589336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 15599336Sdfr struct nfsrv_descript *nfsd; 15609336Sdfr int before_ret; 15619336Sdfr register struct vattr *before_vap; 15629336Sdfr int after_ret; 15639336Sdfr struct vattr *after_vap; 15649336Sdfr struct mbuf **mbp; 15659336Sdfr char **bposp; 15669336Sdfr{ 15679336Sdfr register struct mbuf *mb = *mbp, *mb2; 15689336Sdfr register char *bpos = *bposp; 15699336Sdfr register u_long *tl; 15709336Sdfr 15719336Sdfr if (before_ret) { 15729336Sdfr nfsm_build(tl, u_long *, NFSX_UNSIGNED); 15739336Sdfr *tl = nfs_false; 15749336Sdfr } else { 15759336Sdfr nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED); 15769336Sdfr *tl++ = nfs_true; 15779336Sdfr txdr_hyper(&(before_vap->va_size), tl); 15789336Sdfr tl += 2; 15799336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 15809336Sdfr tl += 2; 15819336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 15829336Sdfr } 15839336Sdfr *bposp = bpos; 15849336Sdfr *mbp = mb; 15859336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 15869336Sdfr} 15879336Sdfr 15889336Sdfrvoid 15899336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 15909336Sdfr struct nfsrv_descript *nfsd; 15919336Sdfr int after_ret; 15929336Sdfr struct vattr *after_vap; 15939336Sdfr struct mbuf **mbp; 15949336Sdfr char **bposp; 15959336Sdfr{ 15969336Sdfr register struct mbuf *mb = *mbp, *mb2; 15979336Sdfr register char *bpos = *bposp; 15989336Sdfr register u_long *tl; 15999336Sdfr register struct nfs_fattr *fp; 16009336Sdfr 16019336Sdfr if (after_ret) { 16029336Sdfr nfsm_build(tl, u_long *, NFSX_UNSIGNED); 16039336Sdfr *tl = nfs_false; 16049336Sdfr } else { 16059336Sdfr nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR); 16069336Sdfr *tl++ = nfs_true; 16079336Sdfr fp = (struct nfs_fattr *)tl; 16089336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 16099336Sdfr } 16109336Sdfr *mbp = mb; 16119336Sdfr *bposp = bpos; 16129336Sdfr} 16139336Sdfr 16149336Sdfrvoid 16159336Sdfrnfsm_srvfattr(nfsd, vap, fp) 16169336Sdfr register struct nfsrv_descript *nfsd; 16179336Sdfr register struct vattr *vap; 16189336Sdfr register struct nfs_fattr *fp; 16199336Sdfr{ 16209336Sdfr 16219336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 16229336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 16239336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 16249336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 16259336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 16269336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 16279336Sdfr txdr_hyper(&vap->va_size, &fp->fa3_size); 16289336Sdfr txdr_hyper(&vap->va_bytes, &fp->fa3_used); 16299336Sdfr fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 16309336Sdfr fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 16319336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 16329336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 16339336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 16349336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 16359336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 16369336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 16379336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 16389336Sdfr } else { 16399336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 16409336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 16419336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 16429336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 16439336Sdfr if (vap->va_type == VFIFO) 16449336Sdfr fp->fa2_rdev = 0xffffffff; 16459336Sdfr else 16469336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 16479336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 16489336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 16499336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 16509336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 16519336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 16529336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 16539336Sdfr } 16549336Sdfr} 16559336Sdfr 16569336Sdfr/* 16571541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 16581541Srgrimes * - look up fsid in mount list (if not found ret error) 16591541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 16601541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 16611541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 16621541Srgrimes */ 16631549Srgrimesint 16649336Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) 16651541Srgrimes fhandle_t *fhp; 16661541Srgrimes int lockflag; 16671541Srgrimes struct vnode **vpp; 16681541Srgrimes struct ucred *cred; 16691541Srgrimes struct nfssvc_sock *slp; 16701541Srgrimes struct mbuf *nam; 16711541Srgrimes int *rdonlyp; 16729336Sdfr int kerbflag; 16731541Srgrimes{ 16741541Srgrimes register struct mount *mp; 16751541Srgrimes register struct nfsuid *uidp; 16761541Srgrimes register int i; 16771541Srgrimes struct ucred *credanon; 16781541Srgrimes int error, exflags; 16791541Srgrimes 16801541Srgrimes *vpp = (struct vnode *)0; 16813305Sphk mp = getvfs(&fhp->fh_fsid); 16823305Sphk if (!mp) 16831541Srgrimes return (ESTALE); 16843305Sphk error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 16853305Sphk if (error) 16861541Srgrimes return (error); 16871541Srgrimes /* 16881541Srgrimes * Check/setup credentials. 16891541Srgrimes */ 16901541Srgrimes if (exflags & MNT_EXKERB) { 16919336Sdfr if (!kerbflag) { 16921541Srgrimes vput(*vpp); 16939336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 16941541Srgrimes } 16959336Sdfr } else if (kerbflag) { 16969336Sdfr vput(*vpp); 16979336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 16981541Srgrimes } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 16991541Srgrimes cred->cr_uid = credanon->cr_uid; 17001541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 17011541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 17023664Sphk cred->cr_ngroups = i; 17031541Srgrimes } 17041541Srgrimes if (exflags & MNT_EXRDONLY) 17051541Srgrimes *rdonlyp = 1; 17061541Srgrimes else 17071541Srgrimes *rdonlyp = 0; 17087969Sdyson 17097969Sdyson nfsrv_vmio(*vpp); 17107969Sdyson 17111541Srgrimes if (!lockflag) 17121541Srgrimes VOP_UNLOCK(*vpp); 17131541Srgrimes return (0); 17141541Srgrimes} 17151541Srgrimes 17161541Srgrimes/* 17171541Srgrimes * This function compares two net addresses by family and returns TRUE 17181541Srgrimes * if they are the same host. 17191541Srgrimes * If there is any doubt, return FALSE. 17201541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 17211541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 17221541Srgrimes */ 17231549Srgrimesint 17241541Srgrimesnetaddr_match(family, haddr, nam) 17251541Srgrimes int family; 17261541Srgrimes union nethostaddr *haddr; 17271541Srgrimes struct mbuf *nam; 17281541Srgrimes{ 17291541Srgrimes register struct sockaddr_in *inetaddr; 17301541Srgrimes 17311541Srgrimes switch (family) { 17321541Srgrimes case AF_INET: 17331541Srgrimes inetaddr = mtod(nam, struct sockaddr_in *); 17341541Srgrimes if (inetaddr->sin_family == AF_INET && 17351541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 17361541Srgrimes return (1); 17371541Srgrimes break; 17381541Srgrimes#ifdef ISO 17391541Srgrimes case AF_ISO: 17401541Srgrimes { 17411541Srgrimes register struct sockaddr_iso *isoaddr1, *isoaddr2; 17421541Srgrimes 17431541Srgrimes isoaddr1 = mtod(nam, struct sockaddr_iso *); 17441541Srgrimes isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 17451541Srgrimes if (isoaddr1->siso_family == AF_ISO && 17461541Srgrimes isoaddr1->siso_nlen > 0 && 17471541Srgrimes isoaddr1->siso_nlen == isoaddr2->siso_nlen && 17481541Srgrimes SAME_ISOADDR(isoaddr1, isoaddr2)) 17491541Srgrimes return (1); 17501541Srgrimes break; 17511541Srgrimes } 17521541Srgrimes#endif /* ISO */ 17531541Srgrimes default: 17541541Srgrimes break; 17551541Srgrimes }; 17561541Srgrimes return (0); 17571541Srgrimes} 17585455Sdg 17599336Sdfrstatic nfsuint64 nfs_nullcookie = { 0, 0 }; 17609336Sdfr/* 17619336Sdfr * This function finds the directory cookie that corresponds to the 17629336Sdfr * logical byte offset given. 17639336Sdfr */ 17649336Sdfrnfsuint64 * 17659336Sdfrnfs_getcookie(np, off, add) 17669336Sdfr register struct nfsnode *np; 17679336Sdfr off_t off; 17689336Sdfr int add; 17699336Sdfr{ 17709336Sdfr register struct nfsdmap *dp, *dp2; 17719336Sdfr register int pos; 17729336Sdfr 17739336Sdfr pos = off / NFS_DIRBLKSIZ; 17749336Sdfr if (pos == 0) { 17759336Sdfr#ifdef DIAGNOSTIC 17769336Sdfr if (add) 17779336Sdfr panic("nfs getcookie add at 0"); 17789336Sdfr#endif 17799336Sdfr return (&nfs_nullcookie); 17809336Sdfr } 17819336Sdfr pos--; 17829336Sdfr dp = np->n_cookies.lh_first; 17839336Sdfr if (!dp) { 17849336Sdfr if (add) { 17859336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 17869336Sdfr M_NFSDIROFF, M_WAITOK); 17879336Sdfr dp->ndm_eocookie = 0; 17889336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 17899336Sdfr } else 17909336Sdfr return ((nfsuint64 *)0); 17919336Sdfr } 17929336Sdfr while (pos >= NFSNUMCOOKIES) { 17939336Sdfr pos -= NFSNUMCOOKIES; 17949336Sdfr if (dp->ndm_list.le_next) { 17959336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 17969336Sdfr pos >= dp->ndm_eocookie) 17979336Sdfr return ((nfsuint64 *)0); 17989336Sdfr dp = dp->ndm_list.le_next; 17999336Sdfr } else if (add) { 18009336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 18019336Sdfr M_NFSDIROFF, M_WAITOK); 18029336Sdfr dp2->ndm_eocookie = 0; 18039336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 18049336Sdfr dp = dp2; 18059336Sdfr } else 18069336Sdfr return ((nfsuint64 *)0); 18079336Sdfr } 18089336Sdfr if (pos >= dp->ndm_eocookie) { 18099336Sdfr if (add) 18109336Sdfr dp->ndm_eocookie = pos + 1; 18119336Sdfr else 18129336Sdfr return ((nfsuint64 *)0); 18139336Sdfr } 18149336Sdfr return (&dp->ndm_cookies[pos]); 18159336Sdfr} 18169336Sdfr 18179336Sdfr/* 18189336Sdfr * Invalidate cached directory information, except for the actual directory 18199336Sdfr * blocks (which are invalidated separately). 18209336Sdfr * Done mainly to avoid the use of stale offset cookies. 18219336Sdfr */ 18229336Sdfrvoid 18239336Sdfrnfs_invaldir(vp) 18249336Sdfr register struct vnode *vp; 18259336Sdfr{ 18269336Sdfr register struct nfsnode *np = VTONFS(vp); 18279336Sdfr 18289336Sdfr#ifdef DIAGNOSTIC 18299336Sdfr if (vp->v_type != VDIR) 18309336Sdfr panic("nfs: invaldir not dir"); 18319336Sdfr#endif 18329336Sdfr np->n_direofoffset = 0; 18339336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 18349336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 18359336Sdfr if (np->n_cookies.lh_first) 18369336Sdfr np->n_cookies.lh_first->ndm_eocookie = 0; 18379336Sdfr} 18389336Sdfr 18399336Sdfr/* 18409336Sdfr * The write verifier has changed (probably due to a server reboot), so all 18419336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 18429336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 18439336Sdfr * flag. Once done the new write verifier can be set for the mount point. 18449336Sdfr */ 18459336Sdfrvoid 18469336Sdfrnfs_clearcommit(mp) 18479336Sdfr struct mount *mp; 18489336Sdfr{ 18499336Sdfr register struct vnode *vp, *nvp; 18509336Sdfr register struct buf *bp, *nbp; 18519336Sdfr int s; 18529336Sdfr 18539336Sdfr s = splbio(); 18549336Sdfrloop: 18559336Sdfr for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 18569336Sdfr if (vp->v_mount != mp) /* Paranoia */ 18579336Sdfr goto loop; 18589336Sdfr nvp = vp->v_mntvnodes.le_next; 18599336Sdfr for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 18609336Sdfr nbp = bp->b_vnbufs.le_next; 18619336Sdfr if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) 18629336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 18639336Sdfr bp->b_flags &= ~B_NEEDCOMMIT; 18649336Sdfr } 18659336Sdfr } 18669336Sdfr splx(s); 18679336Sdfr} 18689336Sdfr 18699336Sdfr/* 18709336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 18719336Sdfr * numbers not specified for the associated procedure. 18729336Sdfr */ 18735455Sdgint 18749336Sdfrnfsrv_errmap(nd, err) 18759336Sdfr struct nfsrv_descript *nd; 18769336Sdfr register int err; 18779336Sdfr{ 18789336Sdfr register short *defaulterrp, *errp; 18799336Sdfr 18809336Sdfr if (nd->nd_flag & ND_NFSV3) { 18819336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 18829336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 18839336Sdfr while (*++errp) { 18849336Sdfr if (*errp == err) 18859336Sdfr return (err); 18869336Sdfr else if (*errp > err) 18879336Sdfr break; 18889336Sdfr } 18899336Sdfr return ((int)*defaulterrp); 18909336Sdfr } else 18919336Sdfr return (err & 0xffff); 18929336Sdfr } 18939336Sdfr if (err <= ELAST) 18949336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 18959336Sdfr return (NFSERR_IO); 18969336Sdfr} 18979336Sdfr 18989336Sdfrint 18995455Sdgnfsrv_vmio( struct vnode *vp) { 19005455Sdg vm_object_t object; 19015455Sdg vm_pager_t pager; 19025455Sdg 19035455Sdg if( (vp == NULL) || (vp->v_type != VREG)) 19045455Sdg return 1; 19055455Sdg 19065455Sdgretry: 19075455Sdg if( (vp->v_flag & VVMIO) == 0) { 19086420Sphk pager = (vm_pager_t) vnode_pager_alloc((caddr_t) vp, 0, 0, 0); 19095455Sdg object = (vm_object_t) vp->v_vmdata; 19105455Sdg if( object->pager != pager) 19115455Sdg panic("nfsrv_vmio: pager/object mismatch"); 19125455Sdg (void) vm_object_lookup( pager); 19135455Sdg pager_cache( object, TRUE); 19145455Sdg vp->v_flag |= VVMIO; 19155455Sdg } else { 19165455Sdg if( (object = (vm_object_t)vp->v_vmdata) && 19175455Sdg (object->flags & OBJ_DEAD)) { 19185455Sdg tsleep( (caddr_t) object, PVM, "nfdead", 0); 19195455Sdg goto retry; 19205455Sdg } 19215455Sdg if( !object) 19225455Sdg panic("nfsrv_vmio: VMIO object missing"); 19235455Sdg pager = object->pager; 19245455Sdg if( !pager) 19255455Sdg panic("nfsrv_vmio: VMIO pager missing"); 19265455Sdg (void) vm_object_lookup( pager); 19275455Sdg } 19285455Sdg return 0; 19295455Sdg} 19305455Sdgint 19315455Sdgnfsrv_vput( struct vnode *vp) { 19325455Sdg if( (vp->v_flag & VVMIO) && vp->v_vmdata) { 19336210Sdg vput( vp); 19345455Sdg vm_object_deallocate( (vm_object_t) vp->v_vmdata); 19356210Sdg } else { 19366210Sdg vput( vp); 19375455Sdg } 19385455Sdg return 0; 19395455Sdg} 19405455Sdgint 19415455Sdgnfsrv_vrele( struct vnode *vp) { 19425455Sdg if( (vp->v_flag & VVMIO) && vp->v_vmdata) { 19436210Sdg vrele( vp); 19445455Sdg vm_object_deallocate( (vm_object_t) vp->v_vmdata); 19456210Sdg } else { 19466210Sdg vrele( vp); 19475455Sdg } 19485455Sdg return 0; 19495455Sdg} 1950