nfs_srvsubs.c revision 31886
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 3731886Sbde * $Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk 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> 4631886Sbde#include <sys/buf.h> 471541Srgrimes#include <sys/proc.h> 481541Srgrimes#include <sys/systm.h> 491541Srgrimes#include <sys/kernel.h> 501541Srgrimes#include <sys/mount.h> 511541Srgrimes#include <sys/vnode.h> 521541Srgrimes#include <sys/namei.h> 531541Srgrimes#include <sys/mbuf.h> 541541Srgrimes#include <sys/socket.h> 551541Srgrimes#include <sys/stat.h> 569336Sdfr#include <sys/malloc.h> 572997Swollman#include <sys/sysent.h> 582997Swollman#include <sys/syscall.h> 591541Srgrimes 603305Sphk#include <vm/vm.h> 6112662Sdg#include <vm/vm_object.h> 6212662Sdg#include <vm/vm_extern.h> 633305Sphk 641541Srgrimes#include <nfs/rpcv2.h> 659336Sdfr#include <nfs/nfsproto.h> 6630808Sbde#include <nfs/nfs.h> 671541Srgrimes#include <nfs/nfsnode.h> 681541Srgrimes#include <nfs/xdr_subs.h> 691541Srgrimes#include <nfs/nfsm_subs.h> 701541Srgrimes#include <nfs/nfsmount.h> 711541Srgrimes#include <nfs/nqnfs.h> 721541Srgrimes#include <nfs/nfsrtt.h> 731541Srgrimes 741541Srgrimes#include <miscfs/specfs/specdev.h> 751541Srgrimes 761541Srgrimes#include <netinet/in.h> 771541Srgrimes#ifdef ISO 781541Srgrimes#include <netiso/iso.h> 791541Srgrimes#endif 801541Srgrimes 811541Srgrimes/* 821541Srgrimes * Data items converted to xdr at startup, since they are constant 831541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 841541Srgrimes */ 851541Srgrimesu_long nfs_xdrneg1; 861541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 879336Sdfr rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 881541Srgrimes rpc_auth_kerb; 899336Sdfru_long nfs_prog, nqnfs_prog, nfs_true, nfs_false; 901541Srgrimes 911541Srgrimes/* And other global data */ 921541Srgrimesstatic u_long nfs_xid = 0; 9312911Sphkstatic enum vtype nv2tov_type[8]= { 9412911Sphk VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9512911Sphk}; 9612911Sphkenum vtype nv3tov_type[8]= { 9712911Sphk VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 9812911Sphk}; 9912911Sphk 10022521Sdysonint nfs_mount_type; 1019336Sdfrint nfs_ticks; 1029336Sdfr 1039759Sbdestruct nfs_reqq nfs_reqq; 1049759Sbdestruct nfssvc_sockhead nfssvc_sockhead; 1059759Sbdeint nfssvc_sockhead_flag; 1069759Sbdestruct nfsd_head nfsd_head; 1079759Sbdeint nfsd_head_flag; 1089759Sbdestruct nfs_bufq nfs_bufq; 1099759Sbdestruct nqtimerhead nqtimerhead; 1109759Sbdestruct nqfhhashhead *nqfhhashtbl; 1119759Sbdeu_long nqfhhash; 1129759Sbde 11313416Sphk#ifndef NFS_NOSERVER 1149336Sdfr/* 1159336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1169336Sdfr */ 1179336Sdfrint nfsv3_procid[NFS_NPROCS] = { 1189336Sdfr NFSPROC_NULL, 1199336Sdfr NFSPROC_GETATTR, 1209336Sdfr NFSPROC_SETATTR, 1219336Sdfr NFSPROC_NOOP, 1229336Sdfr NFSPROC_LOOKUP, 1239336Sdfr NFSPROC_READLINK, 1249336Sdfr NFSPROC_READ, 1259336Sdfr NFSPROC_NOOP, 1269336Sdfr NFSPROC_WRITE, 1279336Sdfr NFSPROC_CREATE, 1289336Sdfr NFSPROC_REMOVE, 1299336Sdfr NFSPROC_RENAME, 1309336Sdfr NFSPROC_LINK, 1319336Sdfr NFSPROC_SYMLINK, 1329336Sdfr NFSPROC_MKDIR, 1339336Sdfr NFSPROC_RMDIR, 1349336Sdfr NFSPROC_READDIR, 1359336Sdfr NFSPROC_FSSTAT, 1369336Sdfr NFSPROC_NOOP, 1379336Sdfr NFSPROC_NOOP, 1389336Sdfr NFSPROC_NOOP, 1399336Sdfr NFSPROC_NOOP, 1409336Sdfr NFSPROC_NOOP, 1419336Sdfr NFSPROC_NOOP, 1429336Sdfr NFSPROC_NOOP, 1439336Sdfr NFSPROC_NOOP 1449336Sdfr}; 1459336Sdfr 14613416Sphk#endif /* NFS_NOSERVER */ 1479336Sdfr/* 1489336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1499336Sdfr */ 1509336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1519336Sdfr NFSV2PROC_NULL, 1529336Sdfr NFSV2PROC_GETATTR, 1539336Sdfr NFSV2PROC_SETATTR, 1549336Sdfr NFSV2PROC_LOOKUP, 1559336Sdfr NFSV2PROC_NOOP, 1569336Sdfr NFSV2PROC_READLINK, 1579336Sdfr NFSV2PROC_READ, 1589336Sdfr NFSV2PROC_WRITE, 1599336Sdfr NFSV2PROC_CREATE, 1609336Sdfr NFSV2PROC_MKDIR, 1619336Sdfr NFSV2PROC_SYMLINK, 1629336Sdfr NFSV2PROC_CREATE, 1639336Sdfr NFSV2PROC_REMOVE, 1649336Sdfr NFSV2PROC_RMDIR, 1659336Sdfr NFSV2PROC_RENAME, 1669336Sdfr NFSV2PROC_LINK, 1679336Sdfr NFSV2PROC_READDIR, 1689336Sdfr NFSV2PROC_NOOP, 1699336Sdfr NFSV2PROC_STATFS, 1709336Sdfr NFSV2PROC_NOOP, 1719336Sdfr NFSV2PROC_NOOP, 1729336Sdfr NFSV2PROC_NOOP, 1739336Sdfr NFSV2PROC_NOOP, 1749336Sdfr NFSV2PROC_NOOP, 1759336Sdfr NFSV2PROC_NOOP, 1769336Sdfr NFSV2PROC_NOOP, 1779336Sdfr}; 1789336Sdfr 17913416Sphk#ifndef NFS_NOSERVER 1809336Sdfr/* 1819336Sdfr * Maps errno values to nfs error numbers. 1829336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1839336Sdfr * RFC 1094. 1849336Sdfr */ 1859336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1869336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1879336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1889336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1899336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 1909336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1919336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 1929336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1939336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1949336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1959336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1969336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1979336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1989336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 1999336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 2009336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2019336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2029336Sdfr NFSERR_IO, 2039336Sdfr}; 2049336Sdfr 2059336Sdfr/* 2069336Sdfr * Maps errno values to nfs error numbers. 2079336Sdfr * Although it is not obvious whether or not NFS clients really care if 2089336Sdfr * a returned error value is in the specified list for the procedure, the 2099336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 2109336Sdfr * X/Open XNFS document is the only specification that defines error values 2119336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 2129336Sdfr * so I have decided to not do this for Version 2. 2139336Sdfr * The first entry is the default error return and the rest are the valid 2149336Sdfr * errors for that RPC in increasing numeric order. 2159336Sdfr */ 2169336Sdfrstatic short nfsv3err_null[] = { 2179336Sdfr 0, 2189336Sdfr 0, 2199336Sdfr}; 2209336Sdfr 2219336Sdfrstatic short nfsv3err_getattr[] = { 2229336Sdfr NFSERR_IO, 2239336Sdfr NFSERR_IO, 2249336Sdfr NFSERR_STALE, 2259336Sdfr NFSERR_BADHANDLE, 2269336Sdfr NFSERR_SERVERFAULT, 2279336Sdfr 0, 2289336Sdfr}; 2299336Sdfr 2309336Sdfrstatic short nfsv3err_setattr[] = { 2319336Sdfr NFSERR_IO, 2329336Sdfr NFSERR_PERM, 2339336Sdfr NFSERR_IO, 2349336Sdfr NFSERR_ACCES, 2359336Sdfr NFSERR_INVAL, 2369336Sdfr NFSERR_NOSPC, 2379336Sdfr NFSERR_ROFS, 2389336Sdfr NFSERR_DQUOT, 2399336Sdfr NFSERR_STALE, 2409336Sdfr NFSERR_BADHANDLE, 2419336Sdfr NFSERR_NOT_SYNC, 2429336Sdfr NFSERR_SERVERFAULT, 2439336Sdfr 0, 2449336Sdfr}; 2459336Sdfr 2469336Sdfrstatic short nfsv3err_lookup[] = { 2479336Sdfr NFSERR_IO, 2489336Sdfr NFSERR_NOENT, 2499336Sdfr NFSERR_IO, 2509336Sdfr NFSERR_ACCES, 2519336Sdfr NFSERR_NOTDIR, 2529336Sdfr NFSERR_NAMETOL, 2539336Sdfr NFSERR_STALE, 2549336Sdfr NFSERR_BADHANDLE, 2559336Sdfr NFSERR_SERVERFAULT, 2569336Sdfr 0, 2579336Sdfr}; 2589336Sdfr 2599336Sdfrstatic short nfsv3err_access[] = { 2609336Sdfr NFSERR_IO, 2619336Sdfr NFSERR_IO, 2629336Sdfr NFSERR_STALE, 2639336Sdfr NFSERR_BADHANDLE, 2649336Sdfr NFSERR_SERVERFAULT, 2659336Sdfr 0, 2669336Sdfr}; 2679336Sdfr 2689336Sdfrstatic short nfsv3err_readlink[] = { 2699336Sdfr NFSERR_IO, 2709336Sdfr NFSERR_IO, 2719336Sdfr NFSERR_ACCES, 2729336Sdfr NFSERR_INVAL, 2739336Sdfr NFSERR_STALE, 2749336Sdfr NFSERR_BADHANDLE, 2759336Sdfr NFSERR_NOTSUPP, 2769336Sdfr NFSERR_SERVERFAULT, 2779336Sdfr 0, 2789336Sdfr}; 2799336Sdfr 2809336Sdfrstatic short nfsv3err_read[] = { 2819336Sdfr NFSERR_IO, 2829336Sdfr NFSERR_IO, 2839336Sdfr NFSERR_NXIO, 2849336Sdfr NFSERR_ACCES, 2859336Sdfr NFSERR_INVAL, 2869336Sdfr NFSERR_STALE, 2879336Sdfr NFSERR_BADHANDLE, 2889336Sdfr NFSERR_SERVERFAULT, 2899336Sdfr 0, 2909336Sdfr}; 2919336Sdfr 2929336Sdfrstatic short nfsv3err_write[] = { 2939336Sdfr NFSERR_IO, 2949336Sdfr NFSERR_IO, 2959336Sdfr NFSERR_ACCES, 2969336Sdfr NFSERR_INVAL, 2979336Sdfr NFSERR_FBIG, 2989336Sdfr NFSERR_NOSPC, 2999336Sdfr NFSERR_ROFS, 3009336Sdfr NFSERR_DQUOT, 3019336Sdfr NFSERR_STALE, 3029336Sdfr NFSERR_BADHANDLE, 3039336Sdfr NFSERR_SERVERFAULT, 3049336Sdfr 0, 3059336Sdfr}; 3069336Sdfr 3079336Sdfrstatic short nfsv3err_create[] = { 3089336Sdfr NFSERR_IO, 3099336Sdfr NFSERR_IO, 3109336Sdfr NFSERR_ACCES, 3119336Sdfr NFSERR_EXIST, 3129336Sdfr NFSERR_NOTDIR, 3139336Sdfr NFSERR_NOSPC, 3149336Sdfr NFSERR_ROFS, 3159336Sdfr NFSERR_NAMETOL, 3169336Sdfr NFSERR_DQUOT, 3179336Sdfr NFSERR_STALE, 3189336Sdfr NFSERR_BADHANDLE, 3199336Sdfr NFSERR_NOTSUPP, 3209336Sdfr NFSERR_SERVERFAULT, 3219336Sdfr 0, 3229336Sdfr}; 3239336Sdfr 3249336Sdfrstatic short nfsv3err_mkdir[] = { 3259336Sdfr NFSERR_IO, 3269336Sdfr NFSERR_IO, 3279336Sdfr NFSERR_ACCES, 3289336Sdfr NFSERR_EXIST, 3299336Sdfr NFSERR_NOTDIR, 3309336Sdfr NFSERR_NOSPC, 3319336Sdfr NFSERR_ROFS, 3329336Sdfr NFSERR_NAMETOL, 3339336Sdfr NFSERR_DQUOT, 3349336Sdfr NFSERR_STALE, 3359336Sdfr NFSERR_BADHANDLE, 3369336Sdfr NFSERR_NOTSUPP, 3379336Sdfr NFSERR_SERVERFAULT, 3389336Sdfr 0, 3399336Sdfr}; 3409336Sdfr 3419336Sdfrstatic short nfsv3err_symlink[] = { 3429336Sdfr NFSERR_IO, 3439336Sdfr NFSERR_IO, 3449336Sdfr NFSERR_ACCES, 3459336Sdfr NFSERR_EXIST, 3469336Sdfr NFSERR_NOTDIR, 3479336Sdfr NFSERR_NOSPC, 3489336Sdfr NFSERR_ROFS, 3499336Sdfr NFSERR_NAMETOL, 3509336Sdfr NFSERR_DQUOT, 3519336Sdfr NFSERR_STALE, 3529336Sdfr NFSERR_BADHANDLE, 3539336Sdfr NFSERR_NOTSUPP, 3549336Sdfr NFSERR_SERVERFAULT, 3559336Sdfr 0, 3569336Sdfr}; 3579336Sdfr 3589336Sdfrstatic short nfsv3err_mknod[] = { 3599336Sdfr NFSERR_IO, 3609336Sdfr NFSERR_IO, 3619336Sdfr NFSERR_ACCES, 3629336Sdfr NFSERR_EXIST, 3639336Sdfr NFSERR_NOTDIR, 3649336Sdfr NFSERR_NOSPC, 3659336Sdfr NFSERR_ROFS, 3669336Sdfr NFSERR_NAMETOL, 3679336Sdfr NFSERR_DQUOT, 3689336Sdfr NFSERR_STALE, 3699336Sdfr NFSERR_BADHANDLE, 3709336Sdfr NFSERR_NOTSUPP, 3719336Sdfr NFSERR_SERVERFAULT, 3729336Sdfr NFSERR_BADTYPE, 3739336Sdfr 0, 3749336Sdfr}; 3759336Sdfr 3769336Sdfrstatic short nfsv3err_remove[] = { 3779336Sdfr NFSERR_IO, 3789336Sdfr NFSERR_NOENT, 3799336Sdfr NFSERR_IO, 3809336Sdfr NFSERR_ACCES, 3819336Sdfr NFSERR_NOTDIR, 3829336Sdfr NFSERR_ROFS, 3839336Sdfr NFSERR_NAMETOL, 3849336Sdfr NFSERR_STALE, 3859336Sdfr NFSERR_BADHANDLE, 3869336Sdfr NFSERR_SERVERFAULT, 3879336Sdfr 0, 3889336Sdfr}; 3899336Sdfr 3909336Sdfrstatic short nfsv3err_rmdir[] = { 3919336Sdfr NFSERR_IO, 3929336Sdfr NFSERR_NOENT, 3939336Sdfr NFSERR_IO, 3949336Sdfr NFSERR_ACCES, 3959336Sdfr NFSERR_EXIST, 3969336Sdfr NFSERR_NOTDIR, 3979336Sdfr NFSERR_INVAL, 3989336Sdfr NFSERR_ROFS, 3999336Sdfr NFSERR_NAMETOL, 4009336Sdfr NFSERR_NOTEMPTY, 4019336Sdfr NFSERR_STALE, 4029336Sdfr NFSERR_BADHANDLE, 4039336Sdfr NFSERR_NOTSUPP, 4049336Sdfr NFSERR_SERVERFAULT, 4059336Sdfr 0, 4069336Sdfr}; 4079336Sdfr 4089336Sdfrstatic short nfsv3err_rename[] = { 4099336Sdfr NFSERR_IO, 4109336Sdfr NFSERR_NOENT, 4119336Sdfr NFSERR_IO, 4129336Sdfr NFSERR_ACCES, 4139336Sdfr NFSERR_EXIST, 4149336Sdfr NFSERR_XDEV, 4159336Sdfr NFSERR_NOTDIR, 4169336Sdfr NFSERR_ISDIR, 4179336Sdfr NFSERR_INVAL, 4189336Sdfr NFSERR_NOSPC, 4199336Sdfr NFSERR_ROFS, 4209336Sdfr NFSERR_MLINK, 4219336Sdfr NFSERR_NAMETOL, 4229336Sdfr NFSERR_NOTEMPTY, 4239336Sdfr NFSERR_DQUOT, 4249336Sdfr NFSERR_STALE, 4259336Sdfr NFSERR_BADHANDLE, 4269336Sdfr NFSERR_NOTSUPP, 4279336Sdfr NFSERR_SERVERFAULT, 4289336Sdfr 0, 4299336Sdfr}; 4309336Sdfr 4319336Sdfrstatic short nfsv3err_link[] = { 4329336Sdfr NFSERR_IO, 4339336Sdfr NFSERR_IO, 4349336Sdfr NFSERR_ACCES, 4359336Sdfr NFSERR_EXIST, 4369336Sdfr NFSERR_XDEV, 4379336Sdfr NFSERR_NOTDIR, 4389336Sdfr NFSERR_INVAL, 4399336Sdfr NFSERR_NOSPC, 4409336Sdfr NFSERR_ROFS, 4419336Sdfr NFSERR_MLINK, 4429336Sdfr NFSERR_NAMETOL, 4439336Sdfr NFSERR_DQUOT, 4449336Sdfr NFSERR_STALE, 4459336Sdfr NFSERR_BADHANDLE, 4469336Sdfr NFSERR_NOTSUPP, 4479336Sdfr NFSERR_SERVERFAULT, 4489336Sdfr 0, 4499336Sdfr}; 4509336Sdfr 4519336Sdfrstatic short nfsv3err_readdir[] = { 4529336Sdfr NFSERR_IO, 4539336Sdfr NFSERR_IO, 4549336Sdfr NFSERR_ACCES, 4559336Sdfr NFSERR_NOTDIR, 4569336Sdfr NFSERR_STALE, 4579336Sdfr NFSERR_BADHANDLE, 4589336Sdfr NFSERR_BAD_COOKIE, 4599336Sdfr NFSERR_TOOSMALL, 4609336Sdfr NFSERR_SERVERFAULT, 4619336Sdfr 0, 4629336Sdfr}; 4639336Sdfr 4649336Sdfrstatic short nfsv3err_readdirplus[] = { 4659336Sdfr NFSERR_IO, 4669336Sdfr NFSERR_IO, 4679336Sdfr NFSERR_ACCES, 4689336Sdfr NFSERR_NOTDIR, 4699336Sdfr NFSERR_STALE, 4709336Sdfr NFSERR_BADHANDLE, 4719336Sdfr NFSERR_BAD_COOKIE, 4729336Sdfr NFSERR_NOTSUPP, 4739336Sdfr NFSERR_TOOSMALL, 4749336Sdfr NFSERR_SERVERFAULT, 4759336Sdfr 0, 4769336Sdfr}; 4779336Sdfr 4789336Sdfrstatic short nfsv3err_fsstat[] = { 4799336Sdfr NFSERR_IO, 4809336Sdfr NFSERR_IO, 4819336Sdfr NFSERR_STALE, 4829336Sdfr NFSERR_BADHANDLE, 4839336Sdfr NFSERR_SERVERFAULT, 4849336Sdfr 0, 4859336Sdfr}; 4869336Sdfr 4879336Sdfrstatic short nfsv3err_fsinfo[] = { 4889336Sdfr NFSERR_STALE, 4899336Sdfr NFSERR_STALE, 4909336Sdfr NFSERR_BADHANDLE, 4919336Sdfr NFSERR_SERVERFAULT, 4929336Sdfr 0, 4939336Sdfr}; 4949336Sdfr 4959336Sdfrstatic short nfsv3err_pathconf[] = { 4969336Sdfr NFSERR_STALE, 4979336Sdfr NFSERR_STALE, 4989336Sdfr NFSERR_BADHANDLE, 4999336Sdfr NFSERR_SERVERFAULT, 5009336Sdfr 0, 5019336Sdfr}; 5029336Sdfr 5039336Sdfrstatic short nfsv3err_commit[] = { 5049336Sdfr NFSERR_IO, 5059336Sdfr NFSERR_IO, 5069336Sdfr NFSERR_STALE, 5079336Sdfr NFSERR_BADHANDLE, 5089336Sdfr NFSERR_SERVERFAULT, 5099336Sdfr 0, 5109336Sdfr}; 5119336Sdfr 5129336Sdfrstatic short *nfsrv_v3errmap[] = { 5139336Sdfr nfsv3err_null, 5149336Sdfr nfsv3err_getattr, 5159336Sdfr nfsv3err_setattr, 5169336Sdfr nfsv3err_lookup, 5179336Sdfr nfsv3err_access, 5189336Sdfr nfsv3err_readlink, 5199336Sdfr nfsv3err_read, 5209336Sdfr nfsv3err_write, 5219336Sdfr nfsv3err_create, 5229336Sdfr nfsv3err_mkdir, 5239336Sdfr nfsv3err_symlink, 5249336Sdfr nfsv3err_mknod, 5259336Sdfr nfsv3err_remove, 5269336Sdfr nfsv3err_rmdir, 5279336Sdfr nfsv3err_rename, 5289336Sdfr nfsv3err_link, 5299336Sdfr nfsv3err_readdir, 5309336Sdfr nfsv3err_readdirplus, 5319336Sdfr nfsv3err_fsstat, 5329336Sdfr nfsv3err_fsinfo, 5339336Sdfr nfsv3err_pathconf, 5349336Sdfr nfsv3err_commit, 5359336Sdfr}; 5369336Sdfr 53713416Sphk#endif /* NFS_NOSERVER */ 53813416Sphk 5391541Srgrimesextern struct nfsrtt nfsrtt; 5401541Srgrimesextern time_t nqnfsstarttime; 5411541Srgrimesextern int nqsrv_clockskew; 5421541Srgrimesextern int nqsrv_writeslack; 5431541Srgrimesextern int nqsrv_maxlease; 5449336Sdfrextern struct nfsstats nfsstats; 5459336Sdfrextern int nqnfs_piggy[NFS_NPROCS]; 5469336Sdfrextern nfstype nfsv2_type[9]; 5479336Sdfrextern nfstype nfsv3_type[9]; 5489336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl; 5499336Sdfrextern u_long nfsnodehash; 5501541Srgrimes 5512997Swollmanstruct getfh_args; 5522997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *); 5532997Swollmanstruct nfssvc_args; 5542997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 5552997Swollman 5563664SphkLIST_HEAD(nfsnodehashhead, nfsnode); 5573664Sphk 55827446Sdfrint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 55927446Sdfr 5601541Srgrimes/* 5611541Srgrimes * Create the header for an rpc request packet 5621541Srgrimes * The hsiz is the size of the rest of the nfs request header. 5631541Srgrimes * (just used to decide if a cluster is a good idea) 5641541Srgrimes */ 5651541Srgrimesstruct mbuf * 5661541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp) 5671541Srgrimes struct vnode *vp; 5681541Srgrimes u_long procid; 5691541Srgrimes int hsiz; 5701541Srgrimes caddr_t *bposp; 5711541Srgrimes{ 5721541Srgrimes register struct mbuf *mb; 5731541Srgrimes register u_long *tl; 5741541Srgrimes register caddr_t bpos; 5751541Srgrimes struct mbuf *mb2; 5761541Srgrimes struct nfsmount *nmp; 5771541Srgrimes int nqflag; 5781541Srgrimes 5791541Srgrimes MGET(mb, M_WAIT, MT_DATA); 5801541Srgrimes if (hsiz >= MINCLSIZE) 5811541Srgrimes MCLGET(mb, M_WAIT); 5821541Srgrimes mb->m_len = 0; 5831541Srgrimes bpos = mtod(mb, caddr_t); 5848876Srgrimes 5851541Srgrimes /* 5861541Srgrimes * For NQNFS, add lease request. 5871541Srgrimes */ 5881541Srgrimes if (vp) { 5891541Srgrimes nmp = VFSTONFS(vp->v_mount); 5901541Srgrimes if (nmp->nm_flag & NFSMNT_NQNFS) { 5911541Srgrimes nqflag = NQNFS_NEEDLEASE(vp, procid); 5921541Srgrimes if (nqflag) { 5931541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 5941541Srgrimes *tl++ = txdr_unsigned(nqflag); 5951541Srgrimes *tl = txdr_unsigned(nmp->nm_leaseterm); 5961541Srgrimes } else { 5971541Srgrimes nfsm_build(tl, u_long *, NFSX_UNSIGNED); 5981541Srgrimes *tl = 0; 5991541Srgrimes } 6001541Srgrimes } 6011541Srgrimes } 6021541Srgrimes /* Finally, return values */ 6031541Srgrimes *bposp = bpos; 6041541Srgrimes return (mb); 6051541Srgrimes} 6061541Srgrimes 6071541Srgrimes/* 6081541Srgrimes * Build the RPC header and fill in the authorization info. 6091541Srgrimes * The authorization string argument is only used when the credentials 6101541Srgrimes * come from outside of the kernel. 6111541Srgrimes * Returns the head of the mbuf list. 6121541Srgrimes */ 6131541Srgrimesstruct mbuf * 6149336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 6159336Sdfr verf_str, mrest, mrest_len, mbp, xidp) 6161541Srgrimes register struct ucred *cr; 6179336Sdfr int nmflag; 6181541Srgrimes int procid; 6191541Srgrimes int auth_type; 6201541Srgrimes int auth_len; 6211541Srgrimes char *auth_str; 6229336Sdfr int verf_len; 6239336Sdfr char *verf_str; 6241541Srgrimes struct mbuf *mrest; 6251541Srgrimes int mrest_len; 6261541Srgrimes struct mbuf **mbp; 6271541Srgrimes u_long *xidp; 6281541Srgrimes{ 6291541Srgrimes register struct mbuf *mb; 6301541Srgrimes register u_long *tl; 6311541Srgrimes register caddr_t bpos; 6321541Srgrimes register int i; 6331541Srgrimes struct mbuf *mreq, *mb2; 6341541Srgrimes int siz, grpsiz, authsiz; 63517186Sdfr struct timeval tv; 63617186Sdfr static u_long base; 6371541Srgrimes 6381541Srgrimes authsiz = nfsm_rndup(auth_len); 6391541Srgrimes MGETHDR(mb, M_WAIT, MT_DATA); 6409336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 6411541Srgrimes MCLGET(mb, M_WAIT); 6429336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 6439336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 6441541Srgrimes } else { 6459336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 6461541Srgrimes } 6471541Srgrimes mb->m_len = 0; 6481541Srgrimes mreq = mb; 6491541Srgrimes bpos = mtod(mb, caddr_t); 6501541Srgrimes 6511541Srgrimes /* 6521541Srgrimes * First the RPC header. 6531541Srgrimes */ 6549336Sdfr nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED); 65517186Sdfr 65617186Sdfr /* 65717186Sdfr * derive initial xid from system time 65817186Sdfr * XXX time is invalid if root not yet mounted 65917186Sdfr */ 66017186Sdfr if (!base && (rootvp)) { 66117186Sdfr microtime(&tv); 66217186Sdfr base = tv.tv_sec << 12; 66317186Sdfr nfs_xid = base; 66417186Sdfr } 66517186Sdfr /* 66617186Sdfr * Skip zero xid if it should ever happen. 66717186Sdfr */ 6681541Srgrimes if (++nfs_xid == 0) 6691541Srgrimes nfs_xid++; 67017186Sdfr 6711541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 6721541Srgrimes *tl++ = rpc_call; 6731541Srgrimes *tl++ = rpc_vers; 6749336Sdfr if (nmflag & NFSMNT_NQNFS) { 6751541Srgrimes *tl++ = txdr_unsigned(NQNFS_PROG); 6769336Sdfr *tl++ = txdr_unsigned(NQNFS_VER3); 6771541Srgrimes } else { 6781541Srgrimes *tl++ = txdr_unsigned(NFS_PROG); 6799336Sdfr if (nmflag & NFSMNT_NFSV3) 6809336Sdfr *tl++ = txdr_unsigned(NFS_VER3); 6819336Sdfr else 6829336Sdfr *tl++ = txdr_unsigned(NFS_VER2); 6831541Srgrimes } 6849336Sdfr if (nmflag & NFSMNT_NFSV3) 6859336Sdfr *tl++ = txdr_unsigned(procid); 6869336Sdfr else 6879336Sdfr *tl++ = txdr_unsigned(nfsv2_procid[procid]); 6881541Srgrimes 6891541Srgrimes /* 6901541Srgrimes * And then the authorization cred. 6911541Srgrimes */ 6921541Srgrimes *tl++ = txdr_unsigned(auth_type); 6931541Srgrimes *tl = txdr_unsigned(authsiz); 6941541Srgrimes switch (auth_type) { 6951541Srgrimes case RPCAUTH_UNIX: 6961541Srgrimes nfsm_build(tl, u_long *, auth_len); 6971541Srgrimes *tl++ = 0; /* stamp ?? */ 6981541Srgrimes *tl++ = 0; /* NULL hostname */ 6991541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 7001541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 7011541Srgrimes grpsiz = (auth_len >> 2) - 5; 7021541Srgrimes *tl++ = txdr_unsigned(grpsiz); 7031541Srgrimes for (i = 1; i <= grpsiz; i++) 7041541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 7051541Srgrimes break; 7069336Sdfr case RPCAUTH_KERB4: 7071541Srgrimes siz = auth_len; 7081541Srgrimes while (siz > 0) { 7091541Srgrimes if (M_TRAILINGSPACE(mb) == 0) { 7101541Srgrimes MGET(mb2, M_WAIT, MT_DATA); 7111541Srgrimes if (siz >= MINCLSIZE) 7121541Srgrimes MCLGET(mb2, M_WAIT); 7131541Srgrimes mb->m_next = mb2; 7141541Srgrimes mb = mb2; 7151541Srgrimes mb->m_len = 0; 7161541Srgrimes bpos = mtod(mb, caddr_t); 7171541Srgrimes } 7181541Srgrimes i = min(siz, M_TRAILINGSPACE(mb)); 7191541Srgrimes bcopy(auth_str, bpos, i); 7201541Srgrimes mb->m_len += i; 7211541Srgrimes auth_str += i; 7221541Srgrimes bpos += i; 7231541Srgrimes siz -= i; 7241541Srgrimes } 7251541Srgrimes if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 7261541Srgrimes for (i = 0; i < siz; i++) 7271541Srgrimes *bpos++ = '\0'; 7281541Srgrimes mb->m_len += siz; 7291541Srgrimes } 7301541Srgrimes break; 7311541Srgrimes }; 7329336Sdfr 7339336Sdfr /* 7349336Sdfr * And the verifier... 7359336Sdfr */ 7369336Sdfr nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 7379336Sdfr if (verf_str) { 7389336Sdfr *tl++ = txdr_unsigned(RPCAUTH_KERB4); 7399336Sdfr *tl = txdr_unsigned(verf_len); 7409336Sdfr siz = verf_len; 7419336Sdfr while (siz > 0) { 7429336Sdfr if (M_TRAILINGSPACE(mb) == 0) { 7439336Sdfr MGET(mb2, M_WAIT, MT_DATA); 7449336Sdfr if (siz >= MINCLSIZE) 7459336Sdfr MCLGET(mb2, M_WAIT); 7469336Sdfr mb->m_next = mb2; 7479336Sdfr mb = mb2; 7489336Sdfr mb->m_len = 0; 7499336Sdfr bpos = mtod(mb, caddr_t); 7509336Sdfr } 7519336Sdfr i = min(siz, M_TRAILINGSPACE(mb)); 7529336Sdfr bcopy(verf_str, bpos, i); 7539336Sdfr mb->m_len += i; 7549336Sdfr verf_str += i; 7559336Sdfr bpos += i; 7569336Sdfr siz -= i; 7579336Sdfr } 7589336Sdfr if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 7599336Sdfr for (i = 0; i < siz; i++) 7609336Sdfr *bpos++ = '\0'; 7619336Sdfr mb->m_len += siz; 7629336Sdfr } 7639336Sdfr } else { 7649336Sdfr *tl++ = txdr_unsigned(RPCAUTH_NULL); 7659336Sdfr *tl = 0; 7669336Sdfr } 7671541Srgrimes mb->m_next = mrest; 7689336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 7691541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 7701541Srgrimes *mbp = mb; 7711541Srgrimes return (mreq); 7721541Srgrimes} 7731541Srgrimes 7741541Srgrimes/* 7751541Srgrimes * copies mbuf chain to the uio scatter/gather list 7761541Srgrimes */ 7771549Srgrimesint 7781541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos) 7791541Srgrimes struct mbuf **mrep; 7801541Srgrimes register struct uio *uiop; 7811541Srgrimes int siz; 7821541Srgrimes caddr_t *dpos; 7831541Srgrimes{ 7841541Srgrimes register char *mbufcp, *uiocp; 7851541Srgrimes register int xfer, left, len; 7861541Srgrimes register struct mbuf *mp; 7871541Srgrimes long uiosiz, rem; 7881541Srgrimes int error = 0; 7891541Srgrimes 7901541Srgrimes mp = *mrep; 7911541Srgrimes mbufcp = *dpos; 7921541Srgrimes len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 7931541Srgrimes rem = nfsm_rndup(siz)-siz; 7941541Srgrimes while (siz > 0) { 7951541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 7961541Srgrimes return (EFBIG); 7971541Srgrimes left = uiop->uio_iov->iov_len; 7981541Srgrimes uiocp = uiop->uio_iov->iov_base; 7991541Srgrimes if (left > siz) 8001541Srgrimes left = siz; 8011541Srgrimes uiosiz = left; 8021541Srgrimes while (left > 0) { 8031541Srgrimes while (len == 0) { 8041541Srgrimes mp = mp->m_next; 8051541Srgrimes if (mp == NULL) 8061541Srgrimes return (EBADRPC); 8071541Srgrimes mbufcp = mtod(mp, caddr_t); 8081541Srgrimes len = mp->m_len; 8091541Srgrimes } 8101541Srgrimes xfer = (left > len) ? len : left; 8111541Srgrimes#ifdef notdef 8121541Srgrimes /* Not Yet.. */ 8131541Srgrimes if (uiop->uio_iov->iov_op != NULL) 8141541Srgrimes (*(uiop->uio_iov->iov_op)) 8151541Srgrimes (mbufcp, uiocp, xfer); 8161541Srgrimes else 8171541Srgrimes#endif 8181541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 8191541Srgrimes bcopy(mbufcp, uiocp, xfer); 8201541Srgrimes else 8211541Srgrimes copyout(mbufcp, uiocp, xfer); 8221541Srgrimes left -= xfer; 8231541Srgrimes len -= xfer; 8241541Srgrimes mbufcp += xfer; 8251541Srgrimes uiocp += xfer; 8261541Srgrimes uiop->uio_offset += xfer; 8271541Srgrimes uiop->uio_resid -= xfer; 8281541Srgrimes } 8291541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 8301541Srgrimes uiop->uio_iovcnt--; 8311541Srgrimes uiop->uio_iov++; 8321541Srgrimes } else { 8331541Srgrimes uiop->uio_iov->iov_base += uiosiz; 8341541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 8351541Srgrimes } 8361541Srgrimes siz -= uiosiz; 8371541Srgrimes } 8381541Srgrimes *dpos = mbufcp; 8391541Srgrimes *mrep = mp; 8401541Srgrimes if (rem > 0) { 8411541Srgrimes if (len < rem) 8421541Srgrimes error = nfs_adv(mrep, dpos, rem, len); 8431541Srgrimes else 8441541Srgrimes *dpos += rem; 8451541Srgrimes } 8461541Srgrimes return (error); 8471541Srgrimes} 8481541Srgrimes 8491541Srgrimes/* 85017186Sdfr * copies a uio scatter/gather list to an mbuf chain. 85117186Sdfr * NOTE: can ony handle iovcnt == 1 8521541Srgrimes */ 8531549Srgrimesint 8541541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos) 8551541Srgrimes register struct uio *uiop; 8561541Srgrimes struct mbuf **mq; 8571541Srgrimes int siz; 8581541Srgrimes caddr_t *bpos; 8591541Srgrimes{ 8601541Srgrimes register char *uiocp; 8611541Srgrimes register struct mbuf *mp, *mp2; 8621541Srgrimes register int xfer, left, mlen; 8631541Srgrimes int uiosiz, clflg, rem; 8641541Srgrimes char *cp; 8651541Srgrimes 86617186Sdfr if (uiop->uio_iovcnt != 1) 86717186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 86817186Sdfr 8691541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 8701541Srgrimes clflg = 1; 8711541Srgrimes else 8721541Srgrimes clflg = 0; 8731541Srgrimes rem = nfsm_rndup(siz)-siz; 8741541Srgrimes mp = mp2 = *mq; 8751541Srgrimes while (siz > 0) { 8761541Srgrimes left = uiop->uio_iov->iov_len; 8771541Srgrimes uiocp = uiop->uio_iov->iov_base; 8781541Srgrimes if (left > siz) 8791541Srgrimes left = siz; 8801541Srgrimes uiosiz = left; 8811541Srgrimes while (left > 0) { 8821541Srgrimes mlen = M_TRAILINGSPACE(mp); 8831541Srgrimes if (mlen == 0) { 8841541Srgrimes MGET(mp, M_WAIT, MT_DATA); 8851541Srgrimes if (clflg) 8861541Srgrimes MCLGET(mp, M_WAIT); 8871541Srgrimes mp->m_len = 0; 8881541Srgrimes mp2->m_next = mp; 8891541Srgrimes mp2 = mp; 8901541Srgrimes mlen = M_TRAILINGSPACE(mp); 8911541Srgrimes } 8921541Srgrimes xfer = (left > mlen) ? mlen : left; 8931541Srgrimes#ifdef notdef 8941541Srgrimes /* Not Yet.. */ 8951541Srgrimes if (uiop->uio_iov->iov_op != NULL) 8961541Srgrimes (*(uiop->uio_iov->iov_op)) 8971541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 8981541Srgrimes else 8991541Srgrimes#endif 9001541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 9011541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9021541Srgrimes else 9031541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9041541Srgrimes mp->m_len += xfer; 9051541Srgrimes left -= xfer; 9061541Srgrimes uiocp += xfer; 9071541Srgrimes uiop->uio_offset += xfer; 9081541Srgrimes uiop->uio_resid -= xfer; 9091541Srgrimes } 91017186Sdfr uiop->uio_iov->iov_base += uiosiz; 91117186Sdfr uiop->uio_iov->iov_len -= uiosiz; 9121541Srgrimes siz -= uiosiz; 9131541Srgrimes } 9141541Srgrimes if (rem > 0) { 9151541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 9161541Srgrimes MGET(mp, M_WAIT, MT_DATA); 9171541Srgrimes mp->m_len = 0; 9181541Srgrimes mp2->m_next = mp; 9191541Srgrimes } 9201541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 9211541Srgrimes for (left = 0; left < rem; left++) 9221541Srgrimes *cp++ = '\0'; 9231541Srgrimes mp->m_len += rem; 9241541Srgrimes *bpos = cp; 9251541Srgrimes } else 9261541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 9271541Srgrimes *mq = mp; 9281541Srgrimes return (0); 9291541Srgrimes} 9301541Srgrimes 9311541Srgrimes/* 9321541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous 9331541Srgrimes * pointed to by returned val. 9341541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 9351541Srgrimes * cases. (The macros use the vars. dpos and dpos2) 9361541Srgrimes */ 9371549Srgrimesint 9381541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2) 9391541Srgrimes struct mbuf **mdp; 9401541Srgrimes caddr_t *dposp; 9411541Srgrimes int siz; 9421541Srgrimes int left; 9431541Srgrimes caddr_t *cp2; 9441541Srgrimes{ 9451541Srgrimes register struct mbuf *mp, *mp2; 9461541Srgrimes register int siz2, xfer; 9471541Srgrimes register caddr_t p; 9481541Srgrimes 9491541Srgrimes mp = *mdp; 9501541Srgrimes while (left == 0) { 9511541Srgrimes *mdp = mp = mp->m_next; 9521541Srgrimes if (mp == NULL) 9531541Srgrimes return (EBADRPC); 9541541Srgrimes left = mp->m_len; 9551541Srgrimes *dposp = mtod(mp, caddr_t); 9561541Srgrimes } 9571541Srgrimes if (left >= siz) { 9581541Srgrimes *cp2 = *dposp; 9591541Srgrimes *dposp += siz; 9601541Srgrimes } else if (mp->m_next == NULL) { 9611541Srgrimes return (EBADRPC); 9621541Srgrimes } else if (siz > MHLEN) { 9631541Srgrimes panic("nfs S too big"); 9641541Srgrimes } else { 9651541Srgrimes MGET(mp2, M_WAIT, MT_DATA); 9661541Srgrimes mp2->m_next = mp->m_next; 9671541Srgrimes mp->m_next = mp2; 9681541Srgrimes mp->m_len -= left; 9691541Srgrimes mp = mp2; 9701541Srgrimes *cp2 = p = mtod(mp, caddr_t); 9711541Srgrimes bcopy(*dposp, p, left); /* Copy what was left */ 9721541Srgrimes siz2 = siz-left; 9731541Srgrimes p += left; 9741541Srgrimes mp2 = mp->m_next; 9751541Srgrimes /* Loop around copying up the siz2 bytes */ 9761541Srgrimes while (siz2 > 0) { 9771541Srgrimes if (mp2 == NULL) 9781541Srgrimes return (EBADRPC); 9791541Srgrimes xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 9801541Srgrimes if (xfer > 0) { 9811541Srgrimes bcopy(mtod(mp2, caddr_t), p, xfer); 9821541Srgrimes NFSMADV(mp2, xfer); 9831541Srgrimes mp2->m_len -= xfer; 9841541Srgrimes p += xfer; 9851541Srgrimes siz2 -= xfer; 9861541Srgrimes } 9871541Srgrimes if (siz2 > 0) 9881541Srgrimes mp2 = mp2->m_next; 9891541Srgrimes } 9901541Srgrimes mp->m_len = siz; 9911541Srgrimes *mdp = mp2; 9921541Srgrimes *dposp = mtod(mp2, caddr_t); 9931541Srgrimes } 9941541Srgrimes return (0); 9951541Srgrimes} 9961541Srgrimes 9971541Srgrimes/* 9981541Srgrimes * Advance the position in the mbuf chain. 9991541Srgrimes */ 10001549Srgrimesint 10011541Srgrimesnfs_adv(mdp, dposp, offs, left) 10021541Srgrimes struct mbuf **mdp; 10031541Srgrimes caddr_t *dposp; 10041541Srgrimes int offs; 10051541Srgrimes int left; 10061541Srgrimes{ 10071541Srgrimes register struct mbuf *m; 10081541Srgrimes register int s; 10091541Srgrimes 10101541Srgrimes m = *mdp; 10111541Srgrimes s = left; 10121541Srgrimes while (s < offs) { 10131541Srgrimes offs -= s; 10141541Srgrimes m = m->m_next; 10151541Srgrimes if (m == NULL) 10161541Srgrimes return (EBADRPC); 10171541Srgrimes s = m->m_len; 10181541Srgrimes } 10191541Srgrimes *mdp = m; 10201541Srgrimes *dposp = mtod(m, caddr_t)+offs; 10211541Srgrimes return (0); 10221541Srgrimes} 10231541Srgrimes 10241541Srgrimes/* 10251541Srgrimes * Copy a string into mbufs for the hard cases... 10261541Srgrimes */ 10271549Srgrimesint 10281541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz) 10291541Srgrimes struct mbuf **mb; 10301541Srgrimes char **bpos; 10311541Srgrimes char *cp; 10321541Srgrimes long siz; 10331541Srgrimes{ 10341549Srgrimes register struct mbuf *m1 = 0, *m2; 10351541Srgrimes long left, xfer, len, tlen; 10361541Srgrimes u_long *tl; 10371541Srgrimes int putsize; 10381541Srgrimes 10391541Srgrimes putsize = 1; 10401541Srgrimes m2 = *mb; 10411541Srgrimes left = M_TRAILINGSPACE(m2); 10421541Srgrimes if (left > 0) { 10431541Srgrimes tl = ((u_long *)(*bpos)); 10441541Srgrimes *tl++ = txdr_unsigned(siz); 10451541Srgrimes putsize = 0; 10461541Srgrimes left -= NFSX_UNSIGNED; 10471541Srgrimes m2->m_len += NFSX_UNSIGNED; 10481541Srgrimes if (left > 0) { 10491541Srgrimes bcopy(cp, (caddr_t) tl, left); 10501541Srgrimes siz -= left; 10511541Srgrimes cp += left; 10521541Srgrimes m2->m_len += left; 10531541Srgrimes left = 0; 10541541Srgrimes } 10551541Srgrimes } 10561541Srgrimes /* Loop around adding mbufs */ 10571541Srgrimes while (siz > 0) { 10581541Srgrimes MGET(m1, M_WAIT, MT_DATA); 10591541Srgrimes if (siz > MLEN) 10601541Srgrimes MCLGET(m1, M_WAIT); 10611541Srgrimes m1->m_len = NFSMSIZ(m1); 10621541Srgrimes m2->m_next = m1; 10631541Srgrimes m2 = m1; 10641541Srgrimes tl = mtod(m1, u_long *); 10651541Srgrimes tlen = 0; 10661541Srgrimes if (putsize) { 10671541Srgrimes *tl++ = txdr_unsigned(siz); 10681541Srgrimes m1->m_len -= NFSX_UNSIGNED; 10691541Srgrimes tlen = NFSX_UNSIGNED; 10701541Srgrimes putsize = 0; 10711541Srgrimes } 10721541Srgrimes if (siz < m1->m_len) { 10731541Srgrimes len = nfsm_rndup(siz); 10741541Srgrimes xfer = siz; 10751541Srgrimes if (xfer < len) 10761541Srgrimes *(tl+(xfer>>2)) = 0; 10771541Srgrimes } else { 10781541Srgrimes xfer = len = m1->m_len; 10791541Srgrimes } 10801541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 10811541Srgrimes m1->m_len = len+tlen; 10821541Srgrimes siz -= xfer; 10831541Srgrimes cp += xfer; 10841541Srgrimes } 10851541Srgrimes *mb = m1; 10861541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 10871541Srgrimes return (0); 10881541Srgrimes} 10891541Srgrimes 10901541Srgrimes/* 10911541Srgrimes * Called once to initialize data structures... 10921541Srgrimes */ 10931549Srgrimesint 109422521Sdysonnfs_init(vfsp) 109522521Sdyson struct vfsconf *vfsp; 10961541Srgrimes{ 10971541Srgrimes register int i; 10981541Srgrimes 10999336Sdfr /* 11009336Sdfr * Check to see if major data structures haven't bloated. 11019336Sdfr */ 11029336Sdfr if (sizeof (struct nfsnode) > NFS_NODEALLOC) { 11039336Sdfr printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); 11049336Sdfr printf("Try reducing NFS_SMALLFH\n"); 11059336Sdfr } 11069336Sdfr if (sizeof (struct nfsmount) > NFS_MNTALLOC) { 11079336Sdfr printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); 11089336Sdfr printf("Try reducing NFS_MUIDHASHSIZ\n"); 11099336Sdfr } 11109336Sdfr if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 11119336Sdfr printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 11129336Sdfr printf("Try reducing NFS_UIDHASHSIZ\n"); 11139336Sdfr } 11149336Sdfr if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 11159336Sdfr printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 11169336Sdfr printf("Try unionizing the nu_nickname and nu_flag fields\n"); 11179336Sdfr } 111822521Sdyson nfs_mount_type = vfsp->vfc_typenum; 11191541Srgrimes nfsrtt.pos = 0; 11201541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 11211541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 11221541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 11231541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 11241541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 11251541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 11261541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 11271541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 11289336Sdfr rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 11291541Srgrimes nfs_prog = txdr_unsigned(NFS_PROG); 11309336Sdfr nqnfs_prog = txdr_unsigned(NQNFS_PROG); 11311541Srgrimes nfs_true = txdr_unsigned(TRUE); 11321541Srgrimes nfs_false = txdr_unsigned(FALSE); 11333664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 11349336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 11359336Sdfr if (nfs_ticks < 1) 11369336Sdfr nfs_ticks = 1; 11371541Srgrimes /* Ensure async daemons disabled */ 113819449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 11391541Srgrimes nfs_iodwant[i] = (struct proc *)0; 114019449Sdfr nfs_iodmount[i] = (struct nfsmount *)0; 114119449Sdfr } 11421541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 114313416Sphk#ifndef NFS_NOSERVER 11441541Srgrimes nfsrv_init(0); /* Init server data structures */ 11451541Srgrimes nfsrv_initcache(); /* Init the server request cache */ 114613416Sphk#endif 11471541Srgrimes 11481541Srgrimes /* 11491541Srgrimes * Initialize the nqnfs server stuff. 11501541Srgrimes */ 11511541Srgrimes if (nqnfsstarttime == 0) { 11521541Srgrimes nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 11531541Srgrimes + nqsrv_clockskew + nqsrv_writeslack; 11541541Srgrimes NQLOADNOVRAM(nqnfsstarttime); 11553664Sphk CIRCLEQ_INIT(&nqtimerhead); 11563664Sphk nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 11571541Srgrimes } 11581541Srgrimes 11591541Srgrimes /* 11601541Srgrimes * Initialize reply list and start timer 11611541Srgrimes */ 11623664Sphk TAILQ_INIT(&nfs_reqq); 116316365Sphk 11643305Sphk nfs_timer(0); 11651549Srgrimes 116616365Sphk 11672997Swollman /* 11682997Swollman * Set up lease_check and lease_updatetime so that other parts 11692997Swollman * of the system can call us, if we are loadable. 11702997Swollman */ 117113416Sphk#ifndef NFS_NOSERVER 117230738Sphk default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; 117313416Sphk#endif 11742997Swollman lease_updatetime = nfs_lease_updatetime; 117522521Sdyson vfsp->vfc_refcount++; /* make us non-unloadable */ 11762997Swollman sysent[SYS_nfssvc].sy_narg = 2; 117730738Sphk sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 117813416Sphk#ifndef NFS_NOSERVER 11792997Swollman sysent[SYS_getfh].sy_narg = 2; 118030738Sphk sysent[SYS_getfh].sy_call = (sy_call_t *)getfh; 11812997Swollman#endif 11822997Swollman 11831549Srgrimes return (0); 11841541Srgrimes} 11851541Srgrimes 11861541Srgrimes/* 11871541Srgrimes * Attribute cache routines. 11881541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 11891541Srgrimes * that are on the mbuf list 11901541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 11911541Srgrimes * error otherwise 11921541Srgrimes */ 11931541Srgrimes 11941541Srgrimes/* 11951541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 11961541Srgrimes * the values on the mbuf list and 11971541Srgrimes * Iff vap not NULL 11981541Srgrimes * copy the attributes to *vaper 11991541Srgrimes */ 12001549Srgrimesint 12011541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper) 12021541Srgrimes struct vnode **vpp; 12031541Srgrimes struct mbuf **mdp; 12041541Srgrimes caddr_t *dposp; 12051541Srgrimes struct vattr *vaper; 12061541Srgrimes{ 12071541Srgrimes register struct vnode *vp = *vpp; 12081541Srgrimes register struct vattr *vap; 12099336Sdfr register struct nfs_fattr *fp; 12103664Sphk register struct nfsnode *np; 12111541Srgrimes register long t1; 12129336Sdfr caddr_t cp2; 12139336Sdfr int error = 0, rdev; 12141541Srgrimes struct mbuf *md; 12151541Srgrimes enum vtype vtyp; 12161541Srgrimes u_short vmode; 12171541Srgrimes struct timespec mtime; 12181541Srgrimes struct vnode *nvp; 12199336Sdfr int v3 = NFS_ISV3(vp); 12201541Srgrimes 12211541Srgrimes md = *mdp; 12229336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 12239336Sdfr if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) 12241541Srgrimes return (error); 12259336Sdfr fp = (struct nfs_fattr *)cp2; 12269336Sdfr if (v3) { 12279336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 12289336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 122916634Sbde rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 123016634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 12319336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 12321541Srgrimes } else { 12339336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 12349336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 12359336Sdfr /* 12369336Sdfr * XXX 12379336Sdfr * 12389336Sdfr * The duplicate information returned in fa_type and fa_mode 12399336Sdfr * is an ambiguity in the NFS version 2 protocol. 12409336Sdfr * 12419336Sdfr * VREG should be taken literally as a regular file. If a 12429336Sdfr * server intents to return some type information differently 12439336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 12449336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 12459336Sdfr * leave the examination of the mode bits even in the VREG 12469336Sdfr * case to avoid breakage for bogus servers, but we make sure 12479336Sdfr * that there are actually type bits set in the upper part of 12489336Sdfr * fa_mode (and failing that, trust the va_type field). 12499336Sdfr * 12509336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 12519336Sdfr * contain any type information (while also introduing sockets 12529336Sdfr * and FIFOs for fa_type). 12539336Sdfr */ 12549336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 12559336Sdfr vtyp = IFTOVT(vmode); 12569336Sdfr rdev = fxdr_unsigned(long, fp->fa2_rdev); 12579336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 12589336Sdfr 12599336Sdfr /* 12609336Sdfr * Really ugly NFSv2 kludge. 12619336Sdfr */ 12629336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 12639336Sdfr vtyp = VFIFO; 12641541Srgrimes } 12659336Sdfr 12661541Srgrimes /* 12671541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 12688876Srgrimes * n_mtime fields. Check to see if it represents a special 12691541Srgrimes * device, and if so, check for a possible alias. Once the 12701541Srgrimes * correct vnode has been obtained, fill in the rest of the 12711541Srgrimes * information. 12721541Srgrimes */ 12731541Srgrimes np = VTONFS(vp); 127410219Sdfr if (vp->v_type != vtyp) { 12759336Sdfr vp->v_type = vtyp; 12761541Srgrimes if (vp->v_type == VFIFO) { 12771541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 12781541Srgrimes } 12791541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 12801541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 12813305Sphk nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 12823305Sphk if (nvp) { 12831541Srgrimes /* 12841541Srgrimes * Discard unneeded vnode, but save its nfsnode. 128522521Sdyson * Since the nfsnode does not have a lock, its 128622521Sdyson * vnode lock has to be carried over. 12871541Srgrimes */ 128822521Sdyson nvp->v_vnlock = vp->v_vnlock; 128922521Sdyson vp->v_vnlock = NULL; 12901541Srgrimes nvp->v_data = vp->v_data; 12911541Srgrimes vp->v_data = NULL; 12921541Srgrimes vp->v_op = spec_vnodeop_p; 12931541Srgrimes vrele(vp); 12941541Srgrimes vgone(vp); 12951541Srgrimes /* 12961541Srgrimes * Reinitialize aliased node. 12971541Srgrimes */ 12981541Srgrimes np->n_vnode = nvp; 12991541Srgrimes *vpp = vp = nvp; 13001541Srgrimes } 13011541Srgrimes } 130218397Snate np->n_mtime = mtime.tv_sec; 13031541Srgrimes } 13041541Srgrimes vap = &np->n_vattr; 13051541Srgrimes vap->va_type = vtyp; 13061541Srgrimes vap->va_mode = (vmode & 07777); 13071541Srgrimes vap->va_rdev = (dev_t)rdev; 13081541Srgrimes vap->va_mtime = mtime; 13091541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 13109336Sdfr if (v3) { 13119336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 13129336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 13139336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 13149336Sdfr fxdr_hyper(&fp->fa3_size, &vap->va_size); 13159336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 13169336Sdfr fxdr_hyper(&fp->fa3_used, &vap->va_bytes); 13179336Sdfr vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]); 13189336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 13199336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 13209336Sdfr vap->va_flags = 0; 13219336Sdfr vap->va_filerev = 0; 13221541Srgrimes } else { 13239336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 13249336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 13259336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 13269336Sdfr vap->va_size = fxdr_unsigned(u_long, fp->fa2_size); 13279336Sdfr vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize); 13289336Sdfr vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE; 13299336Sdfr vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid); 13309336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 13311541Srgrimes vap->va_flags = 0; 133218397Snate vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec); 133318397Snate vap->va_ctime.tv_nsec = 0; 13349336Sdfr vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec); 13351541Srgrimes vap->va_filerev = 0; 13361541Srgrimes } 13371541Srgrimes if (vap->va_size != np->n_size) { 13381541Srgrimes if (vap->va_type == VREG) { 13391541Srgrimes if (np->n_flag & NMODIFIED) { 13401541Srgrimes if (vap->va_size < np->n_size) 13411541Srgrimes vap->va_size = np->n_size; 13421541Srgrimes else 13431541Srgrimes np->n_size = vap->va_size; 13441541Srgrimes } else 13451541Srgrimes np->n_size = vap->va_size; 13461541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 13471541Srgrimes } else 13481541Srgrimes np->n_size = vap->va_size; 13491541Srgrimes } 13501541Srgrimes np->n_attrstamp = time.tv_sec; 13511541Srgrimes if (vaper != NULL) { 13521541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 13531541Srgrimes if (np->n_flag & NCHG) { 13549336Sdfr if (np->n_flag & NACC) 13559336Sdfr vaper->va_atime = np->n_atim; 13569336Sdfr if (np->n_flag & NUPD) 13579336Sdfr vaper->va_mtime = np->n_mtim; 13581541Srgrimes } 13591541Srgrimes } 13601541Srgrimes return (0); 13611541Srgrimes} 13621541Srgrimes 13631541Srgrimes/* 13641541Srgrimes * Check the time stamp 13651541Srgrimes * If the cache is valid, copy contents to *vap and return 0 13661541Srgrimes * otherwise return an error 13671541Srgrimes */ 13681549Srgrimesint 13691541Srgrimesnfs_getattrcache(vp, vaper) 13701541Srgrimes register struct vnode *vp; 13711541Srgrimes struct vattr *vaper; 13721541Srgrimes{ 13731541Srgrimes register struct nfsnode *np = VTONFS(vp); 13741541Srgrimes register struct vattr *vap; 13751541Srgrimes 13769336Sdfr if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 13771541Srgrimes nfsstats.attrcache_misses++; 13781541Srgrimes return (ENOENT); 13791541Srgrimes } 13801541Srgrimes nfsstats.attrcache_hits++; 13811541Srgrimes vap = &np->n_vattr; 13821541Srgrimes if (vap->va_size != np->n_size) { 13831541Srgrimes if (vap->va_type == VREG) { 13841541Srgrimes if (np->n_flag & NMODIFIED) { 13851541Srgrimes if (vap->va_size < np->n_size) 13861541Srgrimes vap->va_size = np->n_size; 13871541Srgrimes else 13881541Srgrimes np->n_size = vap->va_size; 13891541Srgrimes } else 13901541Srgrimes np->n_size = vap->va_size; 13911541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 13921541Srgrimes } else 13931541Srgrimes np->n_size = vap->va_size; 13941541Srgrimes } 13951541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 13961541Srgrimes if (np->n_flag & NCHG) { 13979336Sdfr if (np->n_flag & NACC) 13989336Sdfr vaper->va_atime = np->n_atim; 13999336Sdfr if (np->n_flag & NUPD) 14009336Sdfr vaper->va_mtime = np->n_mtim; 14011541Srgrimes } 14021541Srgrimes return (0); 14031541Srgrimes} 14041541Srgrimes 140513416Sphk#ifndef NFS_NOSERVER 14061541Srgrimes/* 140727446Sdfr * Set up nameidata for a lookup() call and do it. 140827446Sdfr * 140927446Sdfr * If pubflag is set, this call is done for a lookup operation on the 141027446Sdfr * public filehandle. In that case we allow crossing mountpoints and 141127446Sdfr * absolute pathnames. However, the caller is expected to check that 141227446Sdfr * the lookup result is within the public fs, and deny access if 141327446Sdfr * it is not. 14141541Srgrimes */ 14151549Srgrimesint 141627446Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 14171541Srgrimes register struct nameidata *ndp; 14181541Srgrimes fhandle_t *fhp; 14191541Srgrimes int len; 14201541Srgrimes struct nfssvc_sock *slp; 142128270Swollman struct sockaddr *nam; 14221541Srgrimes struct mbuf **mdp; 14231541Srgrimes caddr_t *dposp; 14249336Sdfr struct vnode **retdirp; 14251541Srgrimes struct proc *p; 142627446Sdfr int kerbflag, pubflag; 14271541Srgrimes{ 14281541Srgrimes register int i, rem; 14291541Srgrimes register struct mbuf *md; 143027446Sdfr register char *fromcp, *tocp, *cp; 143127446Sdfr struct iovec aiov; 143227446Sdfr struct uio auio; 14331541Srgrimes struct vnode *dp; 143427446Sdfr int error, rdonly, linklen; 14351541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 14361541Srgrimes 14379336Sdfr *retdirp = (struct vnode *)0; 143829653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 143929653Sdyson 14401541Srgrimes /* 14411541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 14421541Srgrimes * and set the various ndp fields appropriately. 14431541Srgrimes */ 14441541Srgrimes fromcp = *dposp; 14451541Srgrimes tocp = cnp->cn_pnbuf; 14461541Srgrimes md = *mdp; 14471541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 14481541Srgrimes cnp->cn_hash = 0; 14491541Srgrimes for (i = 0; i < len; i++) { 14501541Srgrimes while (rem == 0) { 14511541Srgrimes md = md->m_next; 14521541Srgrimes if (md == NULL) { 14531541Srgrimes error = EBADRPC; 14541541Srgrimes goto out; 14551541Srgrimes } 14561541Srgrimes fromcp = mtod(md, caddr_t); 14571541Srgrimes rem = md->m_len; 14581541Srgrimes } 145927446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 14609336Sdfr error = EACCES; 14611541Srgrimes goto out; 14621541Srgrimes } 14631541Srgrimes cnp->cn_hash += (unsigned char)*fromcp; 14641541Srgrimes *tocp++ = *fromcp++; 14651541Srgrimes rem--; 14661541Srgrimes } 14671541Srgrimes *tocp = '\0'; 14681541Srgrimes *mdp = md; 14691541Srgrimes *dposp = fromcp; 14701541Srgrimes len = nfsm_rndup(len)-len; 14711541Srgrimes if (len > 0) { 14721541Srgrimes if (rem >= len) 14731541Srgrimes *dposp += len; 147427609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 14759336Sdfr goto out; 14761541Srgrimes } 147727446Sdfr 14781541Srgrimes /* 14791541Srgrimes * Extract and set starting directory. 14801541Srgrimes */ 148127446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 148227446Sdfr nam, &rdonly, kerbflag, pubflag); 148327446Sdfr if (error) 14841541Srgrimes goto out; 14851541Srgrimes if (dp->v_type != VDIR) { 148617761Sdyson vrele(dp); 14871541Srgrimes error = ENOTDIR; 14881541Srgrimes goto out; 14891541Srgrimes } 149027446Sdfr 149127446Sdfr if (rdonly) 149227446Sdfr cnp->cn_flags |= RDONLY; 149327446Sdfr 149427609Sdfr *retdirp = dp; 149527609Sdfr 149627446Sdfr if (pubflag) { 149727446Sdfr /* 149827446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 149927446Sdfr * and the 'native path' indicator. 150027446Sdfr */ 150129653Sdyson cp = zalloc(namei_zone); 150227446Sdfr fromcp = cnp->cn_pnbuf; 150327446Sdfr tocp = cp; 150427446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 150527446Sdfr switch ((unsigned char)*fromcp) { 150627446Sdfr case WEBNFS_NATIVE_CHAR: 150727446Sdfr /* 150827446Sdfr * 'Native' path for us is the same 150927446Sdfr * as a path according to the NFS spec, 151027446Sdfr * just skip the escape char. 151127446Sdfr */ 151227446Sdfr fromcp++; 151327446Sdfr break; 151427446Sdfr /* 151527446Sdfr * More may be added in the future, range 0x80-0xff 151627446Sdfr */ 151727446Sdfr default: 151827446Sdfr error = EIO; 151929653Sdyson zfree(namei_zone, cp); 152027446Sdfr goto out; 152127446Sdfr } 152227446Sdfr } 152327446Sdfr /* 152427446Sdfr * Translate the '%' escapes, URL-style. 152527446Sdfr */ 152627446Sdfr while (*fromcp != '\0') { 152727446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 152827446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 152927446Sdfr fromcp++; 153027446Sdfr *tocp++ = HEXSTRTOI(fromcp); 153127446Sdfr fromcp += 2; 153227446Sdfr continue; 153327446Sdfr } else { 153427446Sdfr error = ENOENT; 153529653Sdyson zfree(namei_zone, cp); 153627446Sdfr goto out; 153727446Sdfr } 153827446Sdfr } else 153927446Sdfr *tocp++ = *fromcp++; 154027446Sdfr } 154127446Sdfr *tocp = '\0'; 154229653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 154327446Sdfr cnp->cn_pnbuf = cp; 154427446Sdfr } 154527446Sdfr 154627446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 154727446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 154827446Sdfr 154927446Sdfr if (pubflag) { 155027446Sdfr ndp->ni_rootdir = rootvnode; 155127446Sdfr ndp->ni_loopcnt = 0; 155227446Sdfr if (cnp->cn_pnbuf[0] == '/') 155327446Sdfr dp = rootvnode; 155427446Sdfr } else { 155527609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 155627446Sdfr } 155727446Sdfr 155827446Sdfr cnp->cn_proc = p; 15599336Sdfr VREF(dp); 156027446Sdfr 156127609Sdfr for (;;) { 156227446Sdfr cnp->cn_nameptr = cnp->cn_pnbuf; 15631541Srgrimes ndp->ni_startdir = dp; 15641541Srgrimes /* 15651541Srgrimes * And call lookup() to do the real work 15661541Srgrimes */ 156727609Sdfr error = lookup(ndp); 156827609Sdfr if (error) 156927446Sdfr break; 15701541Srgrimes /* 15711541Srgrimes * Check for encountering a symbolic link 15721541Srgrimes */ 157327446Sdfr if ((cnp->cn_flags & ISSYMLINK) == 0) { 157427446Sdfr nfsrv_object_create(ndp->ni_vp); 157527446Sdfr if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 157627446Sdfr cnp->cn_flags |= HASBUF; 157727446Sdfr return (0); 157827446Sdfr } 157927446Sdfr break; 158027446Sdfr } else { 15811541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 158227446Sdfr VOP_UNLOCK(ndp->ni_dvp, 0, p); 158327446Sdfr if (!pubflag) { 158427446Sdfr vrele(ndp->ni_dvp); 158527446Sdfr vput(ndp->ni_vp); 158627446Sdfr ndp->ni_vp = NULL; 158727446Sdfr error = EINVAL; 158827446Sdfr break; 158927446Sdfr } 159027446Sdfr 159127446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 159227446Sdfr error = ELOOP; 159327446Sdfr break; 159427446Sdfr } 159527609Sdfr if (ndp->ni_pathlen > 1) 159629653Sdyson cp = zalloc(namei_zone); 15971541Srgrimes else 159827446Sdfr cp = cnp->cn_pnbuf; 159927446Sdfr aiov.iov_base = cp; 160027446Sdfr aiov.iov_len = MAXPATHLEN; 160127446Sdfr auio.uio_iov = &aiov; 160227446Sdfr auio.uio_iovcnt = 1; 160327446Sdfr auio.uio_offset = 0; 160427446Sdfr auio.uio_rw = UIO_READ; 160527446Sdfr auio.uio_segflg = UIO_SYSSPACE; 160627446Sdfr auio.uio_procp = (struct proc *)0; 160727446Sdfr auio.uio_resid = MAXPATHLEN; 160827446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 160927446Sdfr if (error) { 161027446Sdfr badlink: 161127446Sdfr if (ndp->ni_pathlen > 1) 161229653Sdyson zfree(namei_zone, cp); 161327446Sdfr break; 161427446Sdfr } 161527446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 161627446Sdfr if (linklen == 0) { 161727446Sdfr error = ENOENT; 161827446Sdfr goto badlink; 161927446Sdfr } 162027446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 162127446Sdfr error = ENAMETOOLONG; 162227446Sdfr goto badlink; 162327446Sdfr } 162427446Sdfr if (ndp->ni_pathlen > 1) { 162527446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 162629653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 162727446Sdfr cnp->cn_pnbuf = cp; 162827446Sdfr } else 162927446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 163027446Sdfr ndp->ni_pathlen += linklen; 16311541Srgrimes vput(ndp->ni_vp); 163227446Sdfr dp = ndp->ni_dvp; 163327446Sdfr /* 163427446Sdfr * Check if root directory should replace current directory. 163527446Sdfr */ 163627446Sdfr if (cnp->cn_pnbuf[0] == '/') { 163727446Sdfr vrele(dp); 163827446Sdfr dp = ndp->ni_rootdir; 163927446Sdfr VREF(dp); 164027446Sdfr } 16411541Srgrimes } 164227609Sdfr } 16431541Srgrimesout: 164429653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 16451541Srgrimes return (error); 16461541Srgrimes} 16471541Srgrimes 16481541Srgrimes/* 16491541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 16501541Srgrimes * boundary and only trims off the back end 16511541Srgrimes */ 16521541Srgrimesvoid 16531541Srgrimesnfsm_adj(mp, len, nul) 16541541Srgrimes struct mbuf *mp; 16551541Srgrimes register int len; 16561541Srgrimes int nul; 16571541Srgrimes{ 16581541Srgrimes register struct mbuf *m; 16591541Srgrimes register int count, i; 16601541Srgrimes register char *cp; 16611541Srgrimes 16621541Srgrimes /* 16631541Srgrimes * Trim from tail. Scan the mbuf chain, 16641541Srgrimes * calculating its length and finding the last mbuf. 16651541Srgrimes * If the adjustment only affects this mbuf, then just 16661541Srgrimes * adjust and return. Otherwise, rescan and truncate 16671541Srgrimes * after the remaining size. 16681541Srgrimes */ 16691541Srgrimes count = 0; 16701541Srgrimes m = mp; 16711541Srgrimes for (;;) { 16721541Srgrimes count += m->m_len; 16731541Srgrimes if (m->m_next == (struct mbuf *)0) 16741541Srgrimes break; 16751541Srgrimes m = m->m_next; 16761541Srgrimes } 16771541Srgrimes if (m->m_len > len) { 16781541Srgrimes m->m_len -= len; 16791541Srgrimes if (nul > 0) { 16801541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 16811541Srgrimes for (i = 0; i < nul; i++) 16821541Srgrimes *cp++ = '\0'; 16831541Srgrimes } 16841541Srgrimes return; 16851541Srgrimes } 16861541Srgrimes count -= len; 16871541Srgrimes if (count < 0) 16881541Srgrimes count = 0; 16891541Srgrimes /* 16901541Srgrimes * Correct length for chain is "count". 16911541Srgrimes * Find the mbuf with last data, adjust its length, 16921541Srgrimes * and toss data from remaining mbufs on chain. 16931541Srgrimes */ 16941541Srgrimes for (m = mp; m; m = m->m_next) { 16951541Srgrimes if (m->m_len >= count) { 16961541Srgrimes m->m_len = count; 16971541Srgrimes if (nul > 0) { 16981541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 16991541Srgrimes for (i = 0; i < nul; i++) 17001541Srgrimes *cp++ = '\0'; 17011541Srgrimes } 17021541Srgrimes break; 17031541Srgrimes } 17041541Srgrimes count -= m->m_len; 17051541Srgrimes } 17063305Sphk for (m = m->m_next;m;m = m->m_next) 17071541Srgrimes m->m_len = 0; 17081541Srgrimes} 17091541Srgrimes 17101541Srgrimes/* 17119336Sdfr * Make these functions instead of macros, so that the kernel text size 17129336Sdfr * doesn't get too big... 17139336Sdfr */ 17149336Sdfrvoid 17159336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 17169336Sdfr struct nfsrv_descript *nfsd; 17179336Sdfr int before_ret; 17189336Sdfr register struct vattr *before_vap; 17199336Sdfr int after_ret; 17209336Sdfr struct vattr *after_vap; 17219336Sdfr struct mbuf **mbp; 17229336Sdfr char **bposp; 17239336Sdfr{ 17249336Sdfr register struct mbuf *mb = *mbp, *mb2; 17259336Sdfr register char *bpos = *bposp; 17269336Sdfr register u_long *tl; 17279336Sdfr 17289336Sdfr if (before_ret) { 17299336Sdfr nfsm_build(tl, u_long *, NFSX_UNSIGNED); 17309336Sdfr *tl = nfs_false; 17319336Sdfr } else { 17329336Sdfr nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED); 17339336Sdfr *tl++ = nfs_true; 17349336Sdfr txdr_hyper(&(before_vap->va_size), tl); 17359336Sdfr tl += 2; 17369336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 17379336Sdfr tl += 2; 17389336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 17399336Sdfr } 17409336Sdfr *bposp = bpos; 17419336Sdfr *mbp = mb; 17429336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 17439336Sdfr} 17449336Sdfr 17459336Sdfrvoid 17469336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 17479336Sdfr struct nfsrv_descript *nfsd; 17489336Sdfr int after_ret; 17499336Sdfr struct vattr *after_vap; 17509336Sdfr struct mbuf **mbp; 17519336Sdfr char **bposp; 17529336Sdfr{ 17539336Sdfr register struct mbuf *mb = *mbp, *mb2; 17549336Sdfr register char *bpos = *bposp; 17559336Sdfr register u_long *tl; 17569336Sdfr register struct nfs_fattr *fp; 17579336Sdfr 17589336Sdfr if (after_ret) { 17599336Sdfr nfsm_build(tl, u_long *, NFSX_UNSIGNED); 17609336Sdfr *tl = nfs_false; 17619336Sdfr } else { 17629336Sdfr nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR); 17639336Sdfr *tl++ = nfs_true; 17649336Sdfr fp = (struct nfs_fattr *)tl; 17659336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 17669336Sdfr } 17679336Sdfr *mbp = mb; 17689336Sdfr *bposp = bpos; 17699336Sdfr} 17709336Sdfr 17719336Sdfrvoid 17729336Sdfrnfsm_srvfattr(nfsd, vap, fp) 17739336Sdfr register struct nfsrv_descript *nfsd; 17749336Sdfr register struct vattr *vap; 17759336Sdfr register struct nfs_fattr *fp; 17769336Sdfr{ 17779336Sdfr 17789336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 17799336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 17809336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 17819336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 17829336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 17839336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 17849336Sdfr txdr_hyper(&vap->va_size, &fp->fa3_size); 17859336Sdfr txdr_hyper(&vap->va_bytes, &fp->fa3_used); 17869336Sdfr fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 17879336Sdfr fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 17889336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 17899336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 17909336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 17919336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 17929336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 17939336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 17949336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 17959336Sdfr } else { 17969336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 17979336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 17989336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 17999336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 18009336Sdfr if (vap->va_type == VFIFO) 18019336Sdfr fp->fa2_rdev = 0xffffffff; 18029336Sdfr else 18039336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 18049336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 18059336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 18069336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 18079336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 18089336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 18099336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 18109336Sdfr } 18119336Sdfr} 18129336Sdfr 18139336Sdfr/* 18141541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 18151541Srgrimes * - look up fsid in mount list (if not found ret error) 18161541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 18171541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 18181541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 18191541Srgrimes */ 18201549Srgrimesint 182127446Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 18221541Srgrimes fhandle_t *fhp; 18231541Srgrimes int lockflag; 18241541Srgrimes struct vnode **vpp; 18251541Srgrimes struct ucred *cred; 18261541Srgrimes struct nfssvc_sock *slp; 182728270Swollman struct sockaddr *nam; 18281541Srgrimes int *rdonlyp; 18299336Sdfr int kerbflag; 183027446Sdfr int pubflag; 18311541Srgrimes{ 183222521Sdyson struct proc *p = curproc; /* XXX */ 18331541Srgrimes register struct mount *mp; 18341541Srgrimes register int i; 18351541Srgrimes struct ucred *credanon; 18361541Srgrimes int error, exflags; 18371541Srgrimes 18381541Srgrimes *vpp = (struct vnode *)0; 183927446Sdfr 184027446Sdfr if (nfs_ispublicfh(fhp)) { 184127446Sdfr if (!pubflag || !nfs_pub.np_valid) 184227446Sdfr return (ESTALE); 184327446Sdfr fhp = &nfs_pub.np_handle; 184427446Sdfr } 184527446Sdfr 184622521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 18473305Sphk if (!mp) 18481541Srgrimes return (ESTALE); 18493305Sphk error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 18503305Sphk if (error) 18511541Srgrimes return (error); 18521541Srgrimes /* 18531541Srgrimes * Check/setup credentials. 18541541Srgrimes */ 18551541Srgrimes if (exflags & MNT_EXKERB) { 18569336Sdfr if (!kerbflag) { 18571541Srgrimes vput(*vpp); 18589336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 18591541Srgrimes } 18609336Sdfr } else if (kerbflag) { 18619336Sdfr vput(*vpp); 18629336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 18631541Srgrimes } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 18641541Srgrimes cred->cr_uid = credanon->cr_uid; 18651541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 18661541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 18673664Sphk cred->cr_ngroups = i; 18681541Srgrimes } 18691541Srgrimes if (exflags & MNT_EXRDONLY) 18701541Srgrimes *rdonlyp = 1; 18711541Srgrimes else 18721541Srgrimes *rdonlyp = 0; 18737969Sdyson 187417761Sdyson nfsrv_object_create(*vpp); 18757969Sdyson 18761541Srgrimes if (!lockflag) 187722521Sdyson VOP_UNLOCK(*vpp, 0, p); 18781541Srgrimes return (0); 18791541Srgrimes} 18801541Srgrimes 188127446Sdfr 188227446Sdfr/* 188327446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 188427446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 188527446Sdfr * transformed this to all zeroes in both cases, so check for it. 188627446Sdfr */ 188727446Sdfrint 188827446Sdfrnfs_ispublicfh(fhp) 188927446Sdfr fhandle_t *fhp; 189027446Sdfr{ 189127446Sdfr char *cp = (char *)fhp; 189227446Sdfr int i; 189327446Sdfr 189427446Sdfr for (i = 0; i < NFSX_V3FH; i++) 189527446Sdfr if (*cp++ != 0) 189627446Sdfr return (FALSE); 189727446Sdfr return (TRUE); 189827446Sdfr} 189927446Sdfr 190013416Sphk#endif /* NFS_NOSERVER */ 19011541Srgrimes/* 19021541Srgrimes * This function compares two net addresses by family and returns TRUE 19031541Srgrimes * if they are the same host. 19041541Srgrimes * If there is any doubt, return FALSE. 19051541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 19061541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 19071541Srgrimes */ 19081549Srgrimesint 19091541Srgrimesnetaddr_match(family, haddr, nam) 19101541Srgrimes int family; 19111541Srgrimes union nethostaddr *haddr; 191228270Swollman struct sockaddr *nam; 19131541Srgrimes{ 19141541Srgrimes register struct sockaddr_in *inetaddr; 19151541Srgrimes 19161541Srgrimes switch (family) { 19171541Srgrimes case AF_INET: 191828270Swollman inetaddr = (struct sockaddr_in *)nam; 19191541Srgrimes if (inetaddr->sin_family == AF_INET && 19201541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 19211541Srgrimes return (1); 19221541Srgrimes break; 19231541Srgrimes#ifdef ISO 19241541Srgrimes case AF_ISO: 19251541Srgrimes { 19261541Srgrimes register struct sockaddr_iso *isoaddr1, *isoaddr2; 19271541Srgrimes 192828270Swollman isoaddr1 = (struct sockaddr_iso *)nam; 192928270Swollman isoaddr2 = (struct sockaddr_iso *)haddr->had_nam; 19301541Srgrimes if (isoaddr1->siso_family == AF_ISO && 19311541Srgrimes isoaddr1->siso_nlen > 0 && 19321541Srgrimes isoaddr1->siso_nlen == isoaddr2->siso_nlen && 19331541Srgrimes SAME_ISOADDR(isoaddr1, isoaddr2)) 19341541Srgrimes return (1); 19351541Srgrimes break; 19361541Srgrimes } 19371541Srgrimes#endif /* ISO */ 19381541Srgrimes default: 19391541Srgrimes break; 19401541Srgrimes }; 19411541Srgrimes return (0); 19421541Srgrimes} 19435455Sdg 19449336Sdfrstatic nfsuint64 nfs_nullcookie = { 0, 0 }; 19459336Sdfr/* 19469336Sdfr * This function finds the directory cookie that corresponds to the 19479336Sdfr * logical byte offset given. 19489336Sdfr */ 19499336Sdfrnfsuint64 * 19509336Sdfrnfs_getcookie(np, off, add) 19519336Sdfr register struct nfsnode *np; 19529336Sdfr off_t off; 19539336Sdfr int add; 19549336Sdfr{ 19559336Sdfr register struct nfsdmap *dp, *dp2; 19569336Sdfr register int pos; 19579336Sdfr 19589336Sdfr pos = off / NFS_DIRBLKSIZ; 19599336Sdfr if (pos == 0) { 19609336Sdfr#ifdef DIAGNOSTIC 19619336Sdfr if (add) 19629336Sdfr panic("nfs getcookie add at 0"); 19639336Sdfr#endif 19649336Sdfr return (&nfs_nullcookie); 19659336Sdfr } 19669336Sdfr pos--; 19679336Sdfr dp = np->n_cookies.lh_first; 19689336Sdfr if (!dp) { 19699336Sdfr if (add) { 19709336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 19719336Sdfr M_NFSDIROFF, M_WAITOK); 19729336Sdfr dp->ndm_eocookie = 0; 19739336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 19749336Sdfr } else 19759336Sdfr return ((nfsuint64 *)0); 19769336Sdfr } 19779336Sdfr while (pos >= NFSNUMCOOKIES) { 19789336Sdfr pos -= NFSNUMCOOKIES; 19799336Sdfr if (dp->ndm_list.le_next) { 19809336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 19819336Sdfr pos >= dp->ndm_eocookie) 19829336Sdfr return ((nfsuint64 *)0); 19839336Sdfr dp = dp->ndm_list.le_next; 19849336Sdfr } else if (add) { 19859336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 19869336Sdfr M_NFSDIROFF, M_WAITOK); 19879336Sdfr dp2->ndm_eocookie = 0; 19889336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 19899336Sdfr dp = dp2; 19909336Sdfr } else 19919336Sdfr return ((nfsuint64 *)0); 19929336Sdfr } 19939336Sdfr if (pos >= dp->ndm_eocookie) { 19949336Sdfr if (add) 19959336Sdfr dp->ndm_eocookie = pos + 1; 19969336Sdfr else 19979336Sdfr return ((nfsuint64 *)0); 19989336Sdfr } 19999336Sdfr return (&dp->ndm_cookies[pos]); 20009336Sdfr} 20019336Sdfr 20029336Sdfr/* 20039336Sdfr * Invalidate cached directory information, except for the actual directory 20049336Sdfr * blocks (which are invalidated separately). 20059336Sdfr * Done mainly to avoid the use of stale offset cookies. 20069336Sdfr */ 20079336Sdfrvoid 20089336Sdfrnfs_invaldir(vp) 20099336Sdfr register struct vnode *vp; 20109336Sdfr{ 20119336Sdfr register struct nfsnode *np = VTONFS(vp); 20129336Sdfr 20139336Sdfr#ifdef DIAGNOSTIC 20149336Sdfr if (vp->v_type != VDIR) 20159336Sdfr panic("nfs: invaldir not dir"); 20169336Sdfr#endif 20179336Sdfr np->n_direofoffset = 0; 20189336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 20199336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 20209336Sdfr if (np->n_cookies.lh_first) 20219336Sdfr np->n_cookies.lh_first->ndm_eocookie = 0; 20229336Sdfr} 20239336Sdfr 20249336Sdfr/* 20259336Sdfr * The write verifier has changed (probably due to a server reboot), so all 20269336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 20279336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 20289336Sdfr * flag. Once done the new write verifier can be set for the mount point. 20299336Sdfr */ 20309336Sdfrvoid 20319336Sdfrnfs_clearcommit(mp) 20329336Sdfr struct mount *mp; 20339336Sdfr{ 20349336Sdfr register struct vnode *vp, *nvp; 20359336Sdfr register struct buf *bp, *nbp; 20369336Sdfr int s; 20379336Sdfr 20389336Sdfr s = splbio(); 20399336Sdfrloop: 20409336Sdfr for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 20419336Sdfr if (vp->v_mount != mp) /* Paranoia */ 20429336Sdfr goto loop; 20439336Sdfr nvp = vp->v_mntvnodes.le_next; 20449336Sdfr for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 20459336Sdfr nbp = bp->b_vnbufs.le_next; 20469336Sdfr if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) 20479336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 20489336Sdfr bp->b_flags &= ~B_NEEDCOMMIT; 20499336Sdfr } 20509336Sdfr } 20519336Sdfr splx(s); 20529336Sdfr} 20539336Sdfr 205413416Sphk#ifndef NFS_NOSERVER 20559336Sdfr/* 20569336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 20579336Sdfr * numbers not specified for the associated procedure. 20589336Sdfr */ 20595455Sdgint 20609336Sdfrnfsrv_errmap(nd, err) 20619336Sdfr struct nfsrv_descript *nd; 20629336Sdfr register int err; 20639336Sdfr{ 20649336Sdfr register short *defaulterrp, *errp; 20659336Sdfr 20669336Sdfr if (nd->nd_flag & ND_NFSV3) { 20679336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 20689336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 20699336Sdfr while (*++errp) { 20709336Sdfr if (*errp == err) 20719336Sdfr return (err); 20729336Sdfr else if (*errp > err) 20739336Sdfr break; 20749336Sdfr } 20759336Sdfr return ((int)*defaulterrp); 20769336Sdfr } else 20779336Sdfr return (err & 0xffff); 20789336Sdfr } 20799336Sdfr if (err <= ELAST) 20809336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 20819336Sdfr return (NFSERR_IO); 20829336Sdfr} 20839336Sdfr 20849336Sdfrint 208531886Sbdenfsrv_object_create(vp) 208631886Sbde struct vnode *vp; 208731886Sbde{ 20885455Sdg 208931886Sbde if (vp == NULL || vp->v_type != VREG) 209031886Sbde return (1); 209131886Sbde return (vfs_object_create(vp, curproc, 209231886Sbde curproc ? curproc->p_ucred : NULL, 1)); 20935455Sdg} 209413416Sphk#endif /* NFS_NOSERVER */ 2095