nfs_srvsubs.c revision 48225
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 * 3636503Speter * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 3748225Smckusick * $Id: nfs_subs.c,v 1.76 1999/06/23 04:44:12 julian 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> 6332011Sbde#include <vm/vm_zone.h> 643305Sphk 651541Srgrimes#include <nfs/rpcv2.h> 669336Sdfr#include <nfs/nfsproto.h> 6730808Sbde#include <nfs/nfs.h> 681541Srgrimes#include <nfs/nfsnode.h> 691541Srgrimes#include <nfs/xdr_subs.h> 701541Srgrimes#include <nfs/nfsm_subs.h> 711541Srgrimes#include <nfs/nfsmount.h> 721541Srgrimes#include <nfs/nqnfs.h> 731541Srgrimes#include <nfs/nfsrtt.h> 741541Srgrimes 751541Srgrimes#include <miscfs/specfs/specdev.h> 761541Srgrimes 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 */ 8636541Speteru_int32_t nfs_xdrneg1; 8736541Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 889336Sdfr rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 891541Srgrimes rpc_auth_kerb; 9036541Speteru_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 911541Srgrimes 921541Srgrimes/* And other global data */ 9336541Speterstatic u_int32_t nfs_xid = 0; 9412911Sphkstatic enum vtype nv2tov_type[8]= { 9512911Sphk VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9612911Sphk}; 9712911Sphkenum vtype nv3tov_type[8]= { 9812911Sphk VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 9912911Sphk}; 10012911Sphk 1019336Sdfrint nfs_ticks; 10242957Sdillonint nfs_pbuf_freecnt = -1; /* start out unlimited */ 1039336Sdfr 1049759Sbdestruct nfs_reqq nfs_reqq; 1059759Sbdestruct nfssvc_sockhead nfssvc_sockhead; 1069759Sbdeint nfssvc_sockhead_flag; 1079759Sbdestruct nfsd_head nfsd_head; 1089759Sbdeint nfsd_head_flag; 1099759Sbdestruct nfs_bufq nfs_bufq; 1109759Sbdestruct nqtimerhead nqtimerhead; 1119759Sbdestruct nqfhhashhead *nqfhhashtbl; 1129759Sbdeu_long nqfhhash; 1139759Sbde 11438894Sbdestatic void (*nfs_prev_lease_updatetime) __P((int)); 11538894Sbdestatic int nfs_prev_nfssvc_sy_narg; 11638894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call; 11738894Sbde 11813416Sphk#ifndef NFS_NOSERVER 11938894Sbde 12038894Sbdestatic vop_t *nfs_prev_vop_lease_check; 12138894Sbdestatic int nfs_prev_getfh_sy_narg; 12238894Sbdestatic sy_call_t *nfs_prev_getfh_sy_call; 12338894Sbde 1249336Sdfr/* 1259336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1269336Sdfr */ 1279336Sdfrint nfsv3_procid[NFS_NPROCS] = { 1289336Sdfr NFSPROC_NULL, 1299336Sdfr NFSPROC_GETATTR, 1309336Sdfr NFSPROC_SETATTR, 1319336Sdfr NFSPROC_NOOP, 1329336Sdfr NFSPROC_LOOKUP, 1339336Sdfr NFSPROC_READLINK, 1349336Sdfr NFSPROC_READ, 1359336Sdfr NFSPROC_NOOP, 1369336Sdfr NFSPROC_WRITE, 1379336Sdfr NFSPROC_CREATE, 1389336Sdfr NFSPROC_REMOVE, 1399336Sdfr NFSPROC_RENAME, 1409336Sdfr NFSPROC_LINK, 1419336Sdfr NFSPROC_SYMLINK, 1429336Sdfr NFSPROC_MKDIR, 1439336Sdfr NFSPROC_RMDIR, 1449336Sdfr NFSPROC_READDIR, 1459336Sdfr NFSPROC_FSSTAT, 1469336Sdfr NFSPROC_NOOP, 1479336Sdfr NFSPROC_NOOP, 1489336Sdfr NFSPROC_NOOP, 1499336Sdfr NFSPROC_NOOP, 1509336Sdfr NFSPROC_NOOP, 1519336Sdfr NFSPROC_NOOP, 1529336Sdfr NFSPROC_NOOP, 1539336Sdfr NFSPROC_NOOP 1549336Sdfr}; 1559336Sdfr 15613416Sphk#endif /* NFS_NOSERVER */ 1579336Sdfr/* 1589336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1599336Sdfr */ 1609336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1619336Sdfr NFSV2PROC_NULL, 1629336Sdfr NFSV2PROC_GETATTR, 1639336Sdfr NFSV2PROC_SETATTR, 1649336Sdfr NFSV2PROC_LOOKUP, 1659336Sdfr NFSV2PROC_NOOP, 1669336Sdfr NFSV2PROC_READLINK, 1679336Sdfr NFSV2PROC_READ, 1689336Sdfr NFSV2PROC_WRITE, 1699336Sdfr NFSV2PROC_CREATE, 1709336Sdfr NFSV2PROC_MKDIR, 1719336Sdfr NFSV2PROC_SYMLINK, 1729336Sdfr NFSV2PROC_CREATE, 1739336Sdfr NFSV2PROC_REMOVE, 1749336Sdfr NFSV2PROC_RMDIR, 1759336Sdfr NFSV2PROC_RENAME, 1769336Sdfr NFSV2PROC_LINK, 1779336Sdfr NFSV2PROC_READDIR, 1789336Sdfr NFSV2PROC_NOOP, 1799336Sdfr NFSV2PROC_STATFS, 1809336Sdfr NFSV2PROC_NOOP, 1819336Sdfr NFSV2PROC_NOOP, 1829336Sdfr NFSV2PROC_NOOP, 1839336Sdfr NFSV2PROC_NOOP, 1849336Sdfr NFSV2PROC_NOOP, 1859336Sdfr NFSV2PROC_NOOP, 1869336Sdfr NFSV2PROC_NOOP, 1879336Sdfr}; 1889336Sdfr 18913416Sphk#ifndef NFS_NOSERVER 1909336Sdfr/* 1919336Sdfr * Maps errno values to nfs error numbers. 1929336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1939336Sdfr * RFC 1094. 1949336Sdfr */ 1959336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1969336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1979336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1989336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1999336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 2009336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2019336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 2029336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2039336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2049336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2059336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2069336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2079336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2089336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 2099336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 2109336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2119336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 21241796Sdt NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 21341796Sdt NFSERR_IO /* << Last is 86 */ 2149336Sdfr}; 2159336Sdfr 2169336Sdfr/* 2179336Sdfr * Maps errno values to nfs error numbers. 2189336Sdfr * Although it is not obvious whether or not NFS clients really care if 2199336Sdfr * a returned error value is in the specified list for the procedure, the 2209336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 2219336Sdfr * X/Open XNFS document is the only specification that defines error values 2229336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 2239336Sdfr * so I have decided to not do this for Version 2. 2249336Sdfr * The first entry is the default error return and the rest are the valid 2259336Sdfr * errors for that RPC in increasing numeric order. 2269336Sdfr */ 2279336Sdfrstatic short nfsv3err_null[] = { 2289336Sdfr 0, 2299336Sdfr 0, 2309336Sdfr}; 2319336Sdfr 2329336Sdfrstatic short nfsv3err_getattr[] = { 2339336Sdfr NFSERR_IO, 2349336Sdfr NFSERR_IO, 2359336Sdfr NFSERR_STALE, 2369336Sdfr NFSERR_BADHANDLE, 2379336Sdfr NFSERR_SERVERFAULT, 2389336Sdfr 0, 2399336Sdfr}; 2409336Sdfr 2419336Sdfrstatic short nfsv3err_setattr[] = { 2429336Sdfr NFSERR_IO, 2439336Sdfr NFSERR_PERM, 2449336Sdfr NFSERR_IO, 2459336Sdfr NFSERR_ACCES, 2469336Sdfr NFSERR_INVAL, 2479336Sdfr NFSERR_NOSPC, 2489336Sdfr NFSERR_ROFS, 2499336Sdfr NFSERR_DQUOT, 2509336Sdfr NFSERR_STALE, 2519336Sdfr NFSERR_BADHANDLE, 2529336Sdfr NFSERR_NOT_SYNC, 2539336Sdfr NFSERR_SERVERFAULT, 2549336Sdfr 0, 2559336Sdfr}; 2569336Sdfr 2579336Sdfrstatic short nfsv3err_lookup[] = { 2589336Sdfr NFSERR_IO, 2599336Sdfr NFSERR_NOENT, 2609336Sdfr NFSERR_IO, 2619336Sdfr NFSERR_ACCES, 2629336Sdfr NFSERR_NOTDIR, 2639336Sdfr NFSERR_NAMETOL, 2649336Sdfr NFSERR_STALE, 2659336Sdfr NFSERR_BADHANDLE, 2669336Sdfr NFSERR_SERVERFAULT, 2679336Sdfr 0, 2689336Sdfr}; 2699336Sdfr 2709336Sdfrstatic short nfsv3err_access[] = { 2719336Sdfr NFSERR_IO, 2729336Sdfr NFSERR_IO, 2739336Sdfr NFSERR_STALE, 2749336Sdfr NFSERR_BADHANDLE, 2759336Sdfr NFSERR_SERVERFAULT, 2769336Sdfr 0, 2779336Sdfr}; 2789336Sdfr 2799336Sdfrstatic short nfsv3err_readlink[] = { 2809336Sdfr NFSERR_IO, 2819336Sdfr NFSERR_IO, 2829336Sdfr NFSERR_ACCES, 2839336Sdfr NFSERR_INVAL, 2849336Sdfr NFSERR_STALE, 2859336Sdfr NFSERR_BADHANDLE, 2869336Sdfr NFSERR_NOTSUPP, 2879336Sdfr NFSERR_SERVERFAULT, 2889336Sdfr 0, 2899336Sdfr}; 2909336Sdfr 2919336Sdfrstatic short nfsv3err_read[] = { 2929336Sdfr NFSERR_IO, 2939336Sdfr NFSERR_IO, 2949336Sdfr NFSERR_NXIO, 2959336Sdfr NFSERR_ACCES, 2969336Sdfr NFSERR_INVAL, 2979336Sdfr NFSERR_STALE, 2989336Sdfr NFSERR_BADHANDLE, 2999336Sdfr NFSERR_SERVERFAULT, 3009336Sdfr 0, 3019336Sdfr}; 3029336Sdfr 3039336Sdfrstatic short nfsv3err_write[] = { 3049336Sdfr NFSERR_IO, 3059336Sdfr NFSERR_IO, 3069336Sdfr NFSERR_ACCES, 3079336Sdfr NFSERR_INVAL, 3089336Sdfr NFSERR_FBIG, 3099336Sdfr NFSERR_NOSPC, 3109336Sdfr NFSERR_ROFS, 3119336Sdfr NFSERR_DQUOT, 3129336Sdfr NFSERR_STALE, 3139336Sdfr NFSERR_BADHANDLE, 3149336Sdfr NFSERR_SERVERFAULT, 3159336Sdfr 0, 3169336Sdfr}; 3179336Sdfr 3189336Sdfrstatic short nfsv3err_create[] = { 3199336Sdfr NFSERR_IO, 3209336Sdfr NFSERR_IO, 3219336Sdfr NFSERR_ACCES, 3229336Sdfr NFSERR_EXIST, 3239336Sdfr NFSERR_NOTDIR, 3249336Sdfr NFSERR_NOSPC, 3259336Sdfr NFSERR_ROFS, 3269336Sdfr NFSERR_NAMETOL, 3279336Sdfr NFSERR_DQUOT, 3289336Sdfr NFSERR_STALE, 3299336Sdfr NFSERR_BADHANDLE, 3309336Sdfr NFSERR_NOTSUPP, 3319336Sdfr NFSERR_SERVERFAULT, 3329336Sdfr 0, 3339336Sdfr}; 3349336Sdfr 3359336Sdfrstatic short nfsv3err_mkdir[] = { 3369336Sdfr NFSERR_IO, 3379336Sdfr NFSERR_IO, 3389336Sdfr NFSERR_ACCES, 3399336Sdfr NFSERR_EXIST, 3409336Sdfr NFSERR_NOTDIR, 3419336Sdfr NFSERR_NOSPC, 3429336Sdfr NFSERR_ROFS, 3439336Sdfr NFSERR_NAMETOL, 3449336Sdfr NFSERR_DQUOT, 3459336Sdfr NFSERR_STALE, 3469336Sdfr NFSERR_BADHANDLE, 3479336Sdfr NFSERR_NOTSUPP, 3489336Sdfr NFSERR_SERVERFAULT, 3499336Sdfr 0, 3509336Sdfr}; 3519336Sdfr 3529336Sdfrstatic short nfsv3err_symlink[] = { 3539336Sdfr NFSERR_IO, 3549336Sdfr NFSERR_IO, 3559336Sdfr NFSERR_ACCES, 3569336Sdfr NFSERR_EXIST, 3579336Sdfr NFSERR_NOTDIR, 3589336Sdfr NFSERR_NOSPC, 3599336Sdfr NFSERR_ROFS, 3609336Sdfr NFSERR_NAMETOL, 3619336Sdfr NFSERR_DQUOT, 3629336Sdfr NFSERR_STALE, 3639336Sdfr NFSERR_BADHANDLE, 3649336Sdfr NFSERR_NOTSUPP, 3659336Sdfr NFSERR_SERVERFAULT, 3669336Sdfr 0, 3679336Sdfr}; 3689336Sdfr 3699336Sdfrstatic short nfsv3err_mknod[] = { 3709336Sdfr NFSERR_IO, 3719336Sdfr NFSERR_IO, 3729336Sdfr NFSERR_ACCES, 3739336Sdfr NFSERR_EXIST, 3749336Sdfr NFSERR_NOTDIR, 3759336Sdfr NFSERR_NOSPC, 3769336Sdfr NFSERR_ROFS, 3779336Sdfr NFSERR_NAMETOL, 3789336Sdfr NFSERR_DQUOT, 3799336Sdfr NFSERR_STALE, 3809336Sdfr NFSERR_BADHANDLE, 3819336Sdfr NFSERR_NOTSUPP, 3829336Sdfr NFSERR_SERVERFAULT, 3839336Sdfr NFSERR_BADTYPE, 3849336Sdfr 0, 3859336Sdfr}; 3869336Sdfr 3879336Sdfrstatic short nfsv3err_remove[] = { 3889336Sdfr NFSERR_IO, 3899336Sdfr NFSERR_NOENT, 3909336Sdfr NFSERR_IO, 3919336Sdfr NFSERR_ACCES, 3929336Sdfr NFSERR_NOTDIR, 3939336Sdfr NFSERR_ROFS, 3949336Sdfr NFSERR_NAMETOL, 3959336Sdfr NFSERR_STALE, 3969336Sdfr NFSERR_BADHANDLE, 3979336Sdfr NFSERR_SERVERFAULT, 3989336Sdfr 0, 3999336Sdfr}; 4009336Sdfr 4019336Sdfrstatic short nfsv3err_rmdir[] = { 4029336Sdfr NFSERR_IO, 4039336Sdfr NFSERR_NOENT, 4049336Sdfr NFSERR_IO, 4059336Sdfr NFSERR_ACCES, 4069336Sdfr NFSERR_EXIST, 4079336Sdfr NFSERR_NOTDIR, 4089336Sdfr NFSERR_INVAL, 4099336Sdfr NFSERR_ROFS, 4109336Sdfr NFSERR_NAMETOL, 4119336Sdfr NFSERR_NOTEMPTY, 4129336Sdfr NFSERR_STALE, 4139336Sdfr NFSERR_BADHANDLE, 4149336Sdfr NFSERR_NOTSUPP, 4159336Sdfr NFSERR_SERVERFAULT, 4169336Sdfr 0, 4179336Sdfr}; 4189336Sdfr 4199336Sdfrstatic short nfsv3err_rename[] = { 4209336Sdfr NFSERR_IO, 4219336Sdfr NFSERR_NOENT, 4229336Sdfr NFSERR_IO, 4239336Sdfr NFSERR_ACCES, 4249336Sdfr NFSERR_EXIST, 4259336Sdfr NFSERR_XDEV, 4269336Sdfr NFSERR_NOTDIR, 4279336Sdfr NFSERR_ISDIR, 4289336Sdfr NFSERR_INVAL, 4299336Sdfr NFSERR_NOSPC, 4309336Sdfr NFSERR_ROFS, 4319336Sdfr NFSERR_MLINK, 4329336Sdfr NFSERR_NAMETOL, 4339336Sdfr NFSERR_NOTEMPTY, 4349336Sdfr NFSERR_DQUOT, 4359336Sdfr NFSERR_STALE, 4369336Sdfr NFSERR_BADHANDLE, 4379336Sdfr NFSERR_NOTSUPP, 4389336Sdfr NFSERR_SERVERFAULT, 4399336Sdfr 0, 4409336Sdfr}; 4419336Sdfr 4429336Sdfrstatic short nfsv3err_link[] = { 4439336Sdfr NFSERR_IO, 4449336Sdfr NFSERR_IO, 4459336Sdfr NFSERR_ACCES, 4469336Sdfr NFSERR_EXIST, 4479336Sdfr NFSERR_XDEV, 4489336Sdfr NFSERR_NOTDIR, 4499336Sdfr NFSERR_INVAL, 4509336Sdfr NFSERR_NOSPC, 4519336Sdfr NFSERR_ROFS, 4529336Sdfr NFSERR_MLINK, 4539336Sdfr NFSERR_NAMETOL, 4549336Sdfr NFSERR_DQUOT, 4559336Sdfr NFSERR_STALE, 4569336Sdfr NFSERR_BADHANDLE, 4579336Sdfr NFSERR_NOTSUPP, 4589336Sdfr NFSERR_SERVERFAULT, 4599336Sdfr 0, 4609336Sdfr}; 4619336Sdfr 4629336Sdfrstatic short nfsv3err_readdir[] = { 4639336Sdfr NFSERR_IO, 4649336Sdfr NFSERR_IO, 4659336Sdfr NFSERR_ACCES, 4669336Sdfr NFSERR_NOTDIR, 4679336Sdfr NFSERR_STALE, 4689336Sdfr NFSERR_BADHANDLE, 4699336Sdfr NFSERR_BAD_COOKIE, 4709336Sdfr NFSERR_TOOSMALL, 4719336Sdfr NFSERR_SERVERFAULT, 4729336Sdfr 0, 4739336Sdfr}; 4749336Sdfr 4759336Sdfrstatic short nfsv3err_readdirplus[] = { 4769336Sdfr NFSERR_IO, 4779336Sdfr NFSERR_IO, 4789336Sdfr NFSERR_ACCES, 4799336Sdfr NFSERR_NOTDIR, 4809336Sdfr NFSERR_STALE, 4819336Sdfr NFSERR_BADHANDLE, 4829336Sdfr NFSERR_BAD_COOKIE, 4839336Sdfr NFSERR_NOTSUPP, 4849336Sdfr NFSERR_TOOSMALL, 4859336Sdfr NFSERR_SERVERFAULT, 4869336Sdfr 0, 4879336Sdfr}; 4889336Sdfr 4899336Sdfrstatic short nfsv3err_fsstat[] = { 4909336Sdfr NFSERR_IO, 4919336Sdfr NFSERR_IO, 4929336Sdfr NFSERR_STALE, 4939336Sdfr NFSERR_BADHANDLE, 4949336Sdfr NFSERR_SERVERFAULT, 4959336Sdfr 0, 4969336Sdfr}; 4979336Sdfr 4989336Sdfrstatic short nfsv3err_fsinfo[] = { 4999336Sdfr NFSERR_STALE, 5009336Sdfr NFSERR_STALE, 5019336Sdfr NFSERR_BADHANDLE, 5029336Sdfr NFSERR_SERVERFAULT, 5039336Sdfr 0, 5049336Sdfr}; 5059336Sdfr 5069336Sdfrstatic short nfsv3err_pathconf[] = { 5079336Sdfr NFSERR_STALE, 5089336Sdfr NFSERR_STALE, 5099336Sdfr NFSERR_BADHANDLE, 5109336Sdfr NFSERR_SERVERFAULT, 5119336Sdfr 0, 5129336Sdfr}; 5139336Sdfr 5149336Sdfrstatic short nfsv3err_commit[] = { 5159336Sdfr NFSERR_IO, 5169336Sdfr NFSERR_IO, 5179336Sdfr NFSERR_STALE, 5189336Sdfr NFSERR_BADHANDLE, 5199336Sdfr NFSERR_SERVERFAULT, 5209336Sdfr 0, 5219336Sdfr}; 5229336Sdfr 5239336Sdfrstatic short *nfsrv_v3errmap[] = { 5249336Sdfr nfsv3err_null, 5259336Sdfr nfsv3err_getattr, 5269336Sdfr nfsv3err_setattr, 5279336Sdfr nfsv3err_lookup, 5289336Sdfr nfsv3err_access, 5299336Sdfr nfsv3err_readlink, 5309336Sdfr nfsv3err_read, 5319336Sdfr nfsv3err_write, 5329336Sdfr nfsv3err_create, 5339336Sdfr nfsv3err_mkdir, 5349336Sdfr nfsv3err_symlink, 5359336Sdfr nfsv3err_mknod, 5369336Sdfr nfsv3err_remove, 5379336Sdfr nfsv3err_rmdir, 5389336Sdfr nfsv3err_rename, 5399336Sdfr nfsv3err_link, 5409336Sdfr nfsv3err_readdir, 5419336Sdfr nfsv3err_readdirplus, 5429336Sdfr nfsv3err_fsstat, 5439336Sdfr nfsv3err_fsinfo, 5449336Sdfr nfsv3err_pathconf, 5459336Sdfr nfsv3err_commit, 5469336Sdfr}; 5479336Sdfr 54813416Sphk#endif /* NFS_NOSERVER */ 54913416Sphk 5501541Srgrimesextern struct nfsrtt nfsrtt; 5511541Srgrimesextern time_t nqnfsstarttime; 5521541Srgrimesextern int nqsrv_clockskew; 5531541Srgrimesextern int nqsrv_writeslack; 5541541Srgrimesextern int nqsrv_maxlease; 5559336Sdfrextern struct nfsstats nfsstats; 5569336Sdfrextern int nqnfs_piggy[NFS_NPROCS]; 5579336Sdfrextern nfstype nfsv2_type[9]; 5589336Sdfrextern nfstype nfsv3_type[9]; 5599336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl; 5609336Sdfrextern u_long nfsnodehash; 5611541Srgrimes 5622997Swollmanstruct getfh_args; 5632997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *); 5642997Swollmanstruct nfssvc_args; 5652997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 5662997Swollman 5673664SphkLIST_HEAD(nfsnodehashhead, nfsnode); 5683664Sphk 56927446Sdfrint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 57027446Sdfr 57134961Sphku_quad_t 57234961Sphknfs_curusec() 57334961Sphk{ 57434961Sphk struct timeval tv; 57534961Sphk 57634961Sphk getmicrotime(&tv); 57734961Sphk return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); 57834961Sphk} 57934961Sphk 5801541Srgrimes/* 5811541Srgrimes * Create the header for an rpc request packet 5821541Srgrimes * The hsiz is the size of the rest of the nfs request header. 5831541Srgrimes * (just used to decide if a cluster is a good idea) 5841541Srgrimes */ 5851541Srgrimesstruct mbuf * 5861541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp) 5871541Srgrimes struct vnode *vp; 5881541Srgrimes u_long procid; 5891541Srgrimes int hsiz; 5901541Srgrimes caddr_t *bposp; 5911541Srgrimes{ 5921541Srgrimes register struct mbuf *mb; 59336541Speter register u_int32_t *tl; 5941541Srgrimes register caddr_t bpos; 5951541Srgrimes struct mbuf *mb2; 5961541Srgrimes struct nfsmount *nmp; 5971541Srgrimes int nqflag; 5981541Srgrimes 5991541Srgrimes MGET(mb, M_WAIT, MT_DATA); 6001541Srgrimes if (hsiz >= MINCLSIZE) 6011541Srgrimes MCLGET(mb, M_WAIT); 6021541Srgrimes mb->m_len = 0; 6031541Srgrimes bpos = mtod(mb, caddr_t); 6048876Srgrimes 6051541Srgrimes /* 6061541Srgrimes * For NQNFS, add lease request. 6071541Srgrimes */ 6081541Srgrimes if (vp) { 6091541Srgrimes nmp = VFSTONFS(vp->v_mount); 6101541Srgrimes if (nmp->nm_flag & NFSMNT_NQNFS) { 6111541Srgrimes nqflag = NQNFS_NEEDLEASE(vp, procid); 6121541Srgrimes if (nqflag) { 61336541Speter nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 6141541Srgrimes *tl++ = txdr_unsigned(nqflag); 6151541Srgrimes *tl = txdr_unsigned(nmp->nm_leaseterm); 6161541Srgrimes } else { 61736541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 6181541Srgrimes *tl = 0; 6191541Srgrimes } 6201541Srgrimes } 6211541Srgrimes } 6221541Srgrimes /* Finally, return values */ 6231541Srgrimes *bposp = bpos; 6241541Srgrimes return (mb); 6251541Srgrimes} 6261541Srgrimes 6271541Srgrimes/* 6281541Srgrimes * Build the RPC header and fill in the authorization info. 6291541Srgrimes * The authorization string argument is only used when the credentials 6301541Srgrimes * come from outside of the kernel. 6311541Srgrimes * Returns the head of the mbuf list. 6321541Srgrimes */ 6331541Srgrimesstruct mbuf * 6349336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 6359336Sdfr verf_str, mrest, mrest_len, mbp, xidp) 6361541Srgrimes register struct ucred *cr; 6379336Sdfr int nmflag; 6381541Srgrimes int procid; 6391541Srgrimes int auth_type; 6401541Srgrimes int auth_len; 6411541Srgrimes char *auth_str; 6429336Sdfr int verf_len; 6439336Sdfr char *verf_str; 6441541Srgrimes struct mbuf *mrest; 6451541Srgrimes int mrest_len; 6461541Srgrimes struct mbuf **mbp; 64736541Speter u_int32_t *xidp; 6481541Srgrimes{ 6491541Srgrimes register struct mbuf *mb; 65036541Speter register u_int32_t *tl; 6511541Srgrimes register caddr_t bpos; 6521541Srgrimes register int i; 6531541Srgrimes struct mbuf *mreq, *mb2; 6541541Srgrimes int siz, grpsiz, authsiz; 6551541Srgrimes 6561541Srgrimes authsiz = nfsm_rndup(auth_len); 6571541Srgrimes MGETHDR(mb, M_WAIT, MT_DATA); 6589336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 6591541Srgrimes MCLGET(mb, M_WAIT); 6609336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 6619336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 6621541Srgrimes } else { 6639336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 6641541Srgrimes } 6651541Srgrimes mb->m_len = 0; 6661541Srgrimes mreq = mb; 6671541Srgrimes bpos = mtod(mb, caddr_t); 6681541Srgrimes 6691541Srgrimes /* 6701541Srgrimes * First the RPC header. 6711541Srgrimes */ 67236541Speter nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 67317186Sdfr 67435066Sphk /* Get a pretty random xid to start with */ 67535066Sphk if (!nfs_xid) 67635066Sphk nfs_xid = random(); 67717186Sdfr /* 67817186Sdfr * Skip zero xid if it should ever happen. 67917186Sdfr */ 6801541Srgrimes if (++nfs_xid == 0) 6811541Srgrimes nfs_xid++; 68217186Sdfr 6831541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 6841541Srgrimes *tl++ = rpc_call; 6851541Srgrimes *tl++ = rpc_vers; 6869336Sdfr if (nmflag & NFSMNT_NQNFS) { 6871541Srgrimes *tl++ = txdr_unsigned(NQNFS_PROG); 6889336Sdfr *tl++ = txdr_unsigned(NQNFS_VER3); 6891541Srgrimes } else { 6901541Srgrimes *tl++ = txdr_unsigned(NFS_PROG); 6919336Sdfr if (nmflag & NFSMNT_NFSV3) 6929336Sdfr *tl++ = txdr_unsigned(NFS_VER3); 6939336Sdfr else 6949336Sdfr *tl++ = txdr_unsigned(NFS_VER2); 6951541Srgrimes } 6969336Sdfr if (nmflag & NFSMNT_NFSV3) 6979336Sdfr *tl++ = txdr_unsigned(procid); 6989336Sdfr else 6999336Sdfr *tl++ = txdr_unsigned(nfsv2_procid[procid]); 7001541Srgrimes 7011541Srgrimes /* 7021541Srgrimes * And then the authorization cred. 7031541Srgrimes */ 7041541Srgrimes *tl++ = txdr_unsigned(auth_type); 7051541Srgrimes *tl = txdr_unsigned(authsiz); 7061541Srgrimes switch (auth_type) { 7071541Srgrimes case RPCAUTH_UNIX: 70836541Speter nfsm_build(tl, u_int32_t *, auth_len); 7091541Srgrimes *tl++ = 0; /* stamp ?? */ 7101541Srgrimes *tl++ = 0; /* NULL hostname */ 7111541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 7121541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 7131541Srgrimes grpsiz = (auth_len >> 2) - 5; 7141541Srgrimes *tl++ = txdr_unsigned(grpsiz); 7151541Srgrimes for (i = 1; i <= grpsiz; i++) 7161541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 7171541Srgrimes break; 7189336Sdfr case RPCAUTH_KERB4: 7191541Srgrimes siz = auth_len; 7201541Srgrimes while (siz > 0) { 7211541Srgrimes if (M_TRAILINGSPACE(mb) == 0) { 7221541Srgrimes MGET(mb2, M_WAIT, MT_DATA); 7231541Srgrimes if (siz >= MINCLSIZE) 7241541Srgrimes MCLGET(mb2, M_WAIT); 7251541Srgrimes mb->m_next = mb2; 7261541Srgrimes mb = mb2; 7271541Srgrimes mb->m_len = 0; 7281541Srgrimes bpos = mtod(mb, caddr_t); 7291541Srgrimes } 7301541Srgrimes i = min(siz, M_TRAILINGSPACE(mb)); 7311541Srgrimes bcopy(auth_str, bpos, i); 7321541Srgrimes mb->m_len += i; 7331541Srgrimes auth_str += i; 7341541Srgrimes bpos += i; 7351541Srgrimes siz -= i; 7361541Srgrimes } 7371541Srgrimes if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 7381541Srgrimes for (i = 0; i < siz; i++) 7391541Srgrimes *bpos++ = '\0'; 7401541Srgrimes mb->m_len += siz; 7411541Srgrimes } 7421541Srgrimes break; 7431541Srgrimes }; 7449336Sdfr 7459336Sdfr /* 7469336Sdfr * And the verifier... 7479336Sdfr */ 74836541Speter nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7499336Sdfr if (verf_str) { 7509336Sdfr *tl++ = txdr_unsigned(RPCAUTH_KERB4); 7519336Sdfr *tl = txdr_unsigned(verf_len); 7529336Sdfr siz = verf_len; 7539336Sdfr while (siz > 0) { 7549336Sdfr if (M_TRAILINGSPACE(mb) == 0) { 7559336Sdfr MGET(mb2, M_WAIT, MT_DATA); 7569336Sdfr if (siz >= MINCLSIZE) 7579336Sdfr MCLGET(mb2, M_WAIT); 7589336Sdfr mb->m_next = mb2; 7599336Sdfr mb = mb2; 7609336Sdfr mb->m_len = 0; 7619336Sdfr bpos = mtod(mb, caddr_t); 7629336Sdfr } 7639336Sdfr i = min(siz, M_TRAILINGSPACE(mb)); 7649336Sdfr bcopy(verf_str, bpos, i); 7659336Sdfr mb->m_len += i; 7669336Sdfr verf_str += i; 7679336Sdfr bpos += i; 7689336Sdfr siz -= i; 7699336Sdfr } 7709336Sdfr if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 7719336Sdfr for (i = 0; i < siz; i++) 7729336Sdfr *bpos++ = '\0'; 7739336Sdfr mb->m_len += siz; 7749336Sdfr } 7759336Sdfr } else { 7769336Sdfr *tl++ = txdr_unsigned(RPCAUTH_NULL); 7779336Sdfr *tl = 0; 7789336Sdfr } 7791541Srgrimes mb->m_next = mrest; 7809336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 7811541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 7821541Srgrimes *mbp = mb; 7831541Srgrimes return (mreq); 7841541Srgrimes} 7851541Srgrimes 7861541Srgrimes/* 7871541Srgrimes * copies mbuf chain to the uio scatter/gather list 7881541Srgrimes */ 7891549Srgrimesint 7901541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos) 7911541Srgrimes struct mbuf **mrep; 7921541Srgrimes register struct uio *uiop; 7931541Srgrimes int siz; 7941541Srgrimes caddr_t *dpos; 7951541Srgrimes{ 7961541Srgrimes register char *mbufcp, *uiocp; 7971541Srgrimes register int xfer, left, len; 7981541Srgrimes register struct mbuf *mp; 7991541Srgrimes long uiosiz, rem; 8001541Srgrimes int error = 0; 8011541Srgrimes 8021541Srgrimes mp = *mrep; 8031541Srgrimes mbufcp = *dpos; 8041541Srgrimes len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 8051541Srgrimes rem = nfsm_rndup(siz)-siz; 8061541Srgrimes while (siz > 0) { 8071541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 8081541Srgrimes return (EFBIG); 8091541Srgrimes left = uiop->uio_iov->iov_len; 8101541Srgrimes uiocp = uiop->uio_iov->iov_base; 8111541Srgrimes if (left > siz) 8121541Srgrimes left = siz; 8131541Srgrimes uiosiz = left; 8141541Srgrimes while (left > 0) { 8151541Srgrimes while (len == 0) { 8161541Srgrimes mp = mp->m_next; 8171541Srgrimes if (mp == NULL) 8181541Srgrimes return (EBADRPC); 8191541Srgrimes mbufcp = mtod(mp, caddr_t); 8201541Srgrimes len = mp->m_len; 8211541Srgrimes } 8221541Srgrimes xfer = (left > len) ? len : left; 8231541Srgrimes#ifdef notdef 8241541Srgrimes /* Not Yet.. */ 8251541Srgrimes if (uiop->uio_iov->iov_op != NULL) 8261541Srgrimes (*(uiop->uio_iov->iov_op)) 8271541Srgrimes (mbufcp, uiocp, xfer); 8281541Srgrimes else 8291541Srgrimes#endif 8301541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 8311541Srgrimes bcopy(mbufcp, uiocp, xfer); 8321541Srgrimes else 8331541Srgrimes copyout(mbufcp, uiocp, xfer); 8341541Srgrimes left -= xfer; 8351541Srgrimes len -= xfer; 8361541Srgrimes mbufcp += xfer; 8371541Srgrimes uiocp += xfer; 8381541Srgrimes uiop->uio_offset += xfer; 8391541Srgrimes uiop->uio_resid -= xfer; 8401541Srgrimes } 8411541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 8421541Srgrimes uiop->uio_iovcnt--; 8431541Srgrimes uiop->uio_iov++; 8441541Srgrimes } else { 8451541Srgrimes uiop->uio_iov->iov_base += uiosiz; 8461541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 8471541Srgrimes } 8481541Srgrimes siz -= uiosiz; 8491541Srgrimes } 8501541Srgrimes *dpos = mbufcp; 8511541Srgrimes *mrep = mp; 8521541Srgrimes if (rem > 0) { 8531541Srgrimes if (len < rem) 8541541Srgrimes error = nfs_adv(mrep, dpos, rem, len); 8551541Srgrimes else 8561541Srgrimes *dpos += rem; 8571541Srgrimes } 8581541Srgrimes return (error); 8591541Srgrimes} 8601541Srgrimes 8611541Srgrimes/* 86217186Sdfr * copies a uio scatter/gather list to an mbuf chain. 86317186Sdfr * NOTE: can ony handle iovcnt == 1 8641541Srgrimes */ 8651549Srgrimesint 8661541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos) 8671541Srgrimes register struct uio *uiop; 8681541Srgrimes struct mbuf **mq; 8691541Srgrimes int siz; 8701541Srgrimes caddr_t *bpos; 8711541Srgrimes{ 8721541Srgrimes register char *uiocp; 8731541Srgrimes register struct mbuf *mp, *mp2; 8741541Srgrimes register int xfer, left, mlen; 8751541Srgrimes int uiosiz, clflg, rem; 8761541Srgrimes char *cp; 8771541Srgrimes 87836519Speter#ifdef DIAGNOSTIC 87917186Sdfr if (uiop->uio_iovcnt != 1) 88017186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 88136519Speter#endif 88217186Sdfr 8831541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 8841541Srgrimes clflg = 1; 8851541Srgrimes else 8861541Srgrimes clflg = 0; 8871541Srgrimes rem = nfsm_rndup(siz)-siz; 8881541Srgrimes mp = mp2 = *mq; 8891541Srgrimes while (siz > 0) { 8901541Srgrimes left = uiop->uio_iov->iov_len; 8911541Srgrimes uiocp = uiop->uio_iov->iov_base; 8921541Srgrimes if (left > siz) 8931541Srgrimes left = siz; 8941541Srgrimes uiosiz = left; 8951541Srgrimes while (left > 0) { 8961541Srgrimes mlen = M_TRAILINGSPACE(mp); 8971541Srgrimes if (mlen == 0) { 8981541Srgrimes MGET(mp, M_WAIT, MT_DATA); 8991541Srgrimes if (clflg) 9001541Srgrimes MCLGET(mp, M_WAIT); 9011541Srgrimes mp->m_len = 0; 9021541Srgrimes mp2->m_next = mp; 9031541Srgrimes mp2 = mp; 9041541Srgrimes mlen = M_TRAILINGSPACE(mp); 9051541Srgrimes } 9061541Srgrimes xfer = (left > mlen) ? mlen : left; 9071541Srgrimes#ifdef notdef 9081541Srgrimes /* Not Yet.. */ 9091541Srgrimes if (uiop->uio_iov->iov_op != NULL) 9101541Srgrimes (*(uiop->uio_iov->iov_op)) 9111541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9121541Srgrimes else 9131541Srgrimes#endif 9141541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 9151541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9161541Srgrimes else 9171541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9181541Srgrimes mp->m_len += xfer; 9191541Srgrimes left -= xfer; 9201541Srgrimes uiocp += xfer; 9211541Srgrimes uiop->uio_offset += xfer; 9221541Srgrimes uiop->uio_resid -= xfer; 9231541Srgrimes } 92417186Sdfr uiop->uio_iov->iov_base += uiosiz; 92517186Sdfr uiop->uio_iov->iov_len -= uiosiz; 9261541Srgrimes siz -= uiosiz; 9271541Srgrimes } 9281541Srgrimes if (rem > 0) { 9291541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 9301541Srgrimes MGET(mp, M_WAIT, MT_DATA); 9311541Srgrimes mp->m_len = 0; 9321541Srgrimes mp2->m_next = mp; 9331541Srgrimes } 9341541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 9351541Srgrimes for (left = 0; left < rem; left++) 9361541Srgrimes *cp++ = '\0'; 9371541Srgrimes mp->m_len += rem; 9381541Srgrimes *bpos = cp; 9391541Srgrimes } else 9401541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 9411541Srgrimes *mq = mp; 9421541Srgrimes return (0); 9431541Srgrimes} 9441541Srgrimes 9451541Srgrimes/* 9461541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous 9471541Srgrimes * pointed to by returned val. 9481541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 9491541Srgrimes * cases. (The macros use the vars. dpos and dpos2) 9501541Srgrimes */ 9511549Srgrimesint 9521541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2) 9531541Srgrimes struct mbuf **mdp; 9541541Srgrimes caddr_t *dposp; 9551541Srgrimes int siz; 9561541Srgrimes int left; 9571541Srgrimes caddr_t *cp2; 9581541Srgrimes{ 9591541Srgrimes register struct mbuf *mp, *mp2; 9601541Srgrimes register int siz2, xfer; 9611541Srgrimes register caddr_t p; 9621541Srgrimes 9631541Srgrimes mp = *mdp; 9641541Srgrimes while (left == 0) { 9651541Srgrimes *mdp = mp = mp->m_next; 9661541Srgrimes if (mp == NULL) 9671541Srgrimes return (EBADRPC); 9681541Srgrimes left = mp->m_len; 9691541Srgrimes *dposp = mtod(mp, caddr_t); 9701541Srgrimes } 9711541Srgrimes if (left >= siz) { 9721541Srgrimes *cp2 = *dposp; 9731541Srgrimes *dposp += siz; 9741541Srgrimes } else if (mp->m_next == NULL) { 9751541Srgrimes return (EBADRPC); 9761541Srgrimes } else if (siz > MHLEN) { 9771541Srgrimes panic("nfs S too big"); 9781541Srgrimes } else { 9791541Srgrimes MGET(mp2, M_WAIT, MT_DATA); 9801541Srgrimes mp2->m_next = mp->m_next; 9811541Srgrimes mp->m_next = mp2; 9821541Srgrimes mp->m_len -= left; 9831541Srgrimes mp = mp2; 9841541Srgrimes *cp2 = p = mtod(mp, caddr_t); 9851541Srgrimes bcopy(*dposp, p, left); /* Copy what was left */ 9861541Srgrimes siz2 = siz-left; 9871541Srgrimes p += left; 9881541Srgrimes mp2 = mp->m_next; 9891541Srgrimes /* Loop around copying up the siz2 bytes */ 9901541Srgrimes while (siz2 > 0) { 9911541Srgrimes if (mp2 == NULL) 9921541Srgrimes return (EBADRPC); 9931541Srgrimes xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 9941541Srgrimes if (xfer > 0) { 9951541Srgrimes bcopy(mtod(mp2, caddr_t), p, xfer); 9961541Srgrimes NFSMADV(mp2, xfer); 9971541Srgrimes mp2->m_len -= xfer; 9981541Srgrimes p += xfer; 9991541Srgrimes siz2 -= xfer; 10001541Srgrimes } 10011541Srgrimes if (siz2 > 0) 10021541Srgrimes mp2 = mp2->m_next; 10031541Srgrimes } 10041541Srgrimes mp->m_len = siz; 10051541Srgrimes *mdp = mp2; 10061541Srgrimes *dposp = mtod(mp2, caddr_t); 10071541Srgrimes } 10081541Srgrimes return (0); 10091541Srgrimes} 10101541Srgrimes 10111541Srgrimes/* 10121541Srgrimes * Advance the position in the mbuf chain. 10131541Srgrimes */ 10141549Srgrimesint 10151541Srgrimesnfs_adv(mdp, dposp, offs, left) 10161541Srgrimes struct mbuf **mdp; 10171541Srgrimes caddr_t *dposp; 10181541Srgrimes int offs; 10191541Srgrimes int left; 10201541Srgrimes{ 10211541Srgrimes register struct mbuf *m; 10221541Srgrimes register int s; 10231541Srgrimes 10241541Srgrimes m = *mdp; 10251541Srgrimes s = left; 10261541Srgrimes while (s < offs) { 10271541Srgrimes offs -= s; 10281541Srgrimes m = m->m_next; 10291541Srgrimes if (m == NULL) 10301541Srgrimes return (EBADRPC); 10311541Srgrimes s = m->m_len; 10321541Srgrimes } 10331541Srgrimes *mdp = m; 10341541Srgrimes *dposp = mtod(m, caddr_t)+offs; 10351541Srgrimes return (0); 10361541Srgrimes} 10371541Srgrimes 10381541Srgrimes/* 10391541Srgrimes * Copy a string into mbufs for the hard cases... 10401541Srgrimes */ 10411549Srgrimesint 10421541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz) 10431541Srgrimes struct mbuf **mb; 10441541Srgrimes char **bpos; 104536511Speter const char *cp; 10461541Srgrimes long siz; 10471541Srgrimes{ 104836519Speter register struct mbuf *m1 = NULL, *m2; 10491541Srgrimes long left, xfer, len, tlen; 105036541Speter u_int32_t *tl; 10511541Srgrimes int putsize; 10521541Srgrimes 10531541Srgrimes putsize = 1; 10541541Srgrimes m2 = *mb; 10551541Srgrimes left = M_TRAILINGSPACE(m2); 10561541Srgrimes if (left > 0) { 105736541Speter tl = ((u_int32_t *)(*bpos)); 10581541Srgrimes *tl++ = txdr_unsigned(siz); 10591541Srgrimes putsize = 0; 10601541Srgrimes left -= NFSX_UNSIGNED; 10611541Srgrimes m2->m_len += NFSX_UNSIGNED; 10621541Srgrimes if (left > 0) { 10631541Srgrimes bcopy(cp, (caddr_t) tl, left); 10641541Srgrimes siz -= left; 10651541Srgrimes cp += left; 10661541Srgrimes m2->m_len += left; 10671541Srgrimes left = 0; 10681541Srgrimes } 10691541Srgrimes } 10701541Srgrimes /* Loop around adding mbufs */ 10711541Srgrimes while (siz > 0) { 10721541Srgrimes MGET(m1, M_WAIT, MT_DATA); 10731541Srgrimes if (siz > MLEN) 10741541Srgrimes MCLGET(m1, M_WAIT); 10751541Srgrimes m1->m_len = NFSMSIZ(m1); 10761541Srgrimes m2->m_next = m1; 10771541Srgrimes m2 = m1; 107836541Speter tl = mtod(m1, u_int32_t *); 10791541Srgrimes tlen = 0; 10801541Srgrimes if (putsize) { 10811541Srgrimes *tl++ = txdr_unsigned(siz); 10821541Srgrimes m1->m_len -= NFSX_UNSIGNED; 10831541Srgrimes tlen = NFSX_UNSIGNED; 10841541Srgrimes putsize = 0; 10851541Srgrimes } 10861541Srgrimes if (siz < m1->m_len) { 10871541Srgrimes len = nfsm_rndup(siz); 10881541Srgrimes xfer = siz; 10891541Srgrimes if (xfer < len) 10901541Srgrimes *(tl+(xfer>>2)) = 0; 10911541Srgrimes } else { 10921541Srgrimes xfer = len = m1->m_len; 10931541Srgrimes } 10941541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 10951541Srgrimes m1->m_len = len+tlen; 10961541Srgrimes siz -= xfer; 10971541Srgrimes cp += xfer; 10981541Srgrimes } 10991541Srgrimes *mb = m1; 11001541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 11011541Srgrimes return (0); 11021541Srgrimes} 11031541Srgrimes 11041541Srgrimes/* 11051541Srgrimes * Called once to initialize data structures... 11061541Srgrimes */ 11071549Srgrimesint 110822521Sdysonnfs_init(vfsp) 110922521Sdyson struct vfsconf *vfsp; 11101541Srgrimes{ 11111541Srgrimes register int i; 11121541Srgrimes 111336329Speter nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 111436329Speter 11159336Sdfr /* 11169336Sdfr * Check to see if major data structures haven't bloated. 11179336Sdfr */ 11189336Sdfr if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 11199336Sdfr printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 11209336Sdfr printf("Try reducing NFS_UIDHASHSIZ\n"); 11219336Sdfr } 11229336Sdfr if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 11239336Sdfr printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 11249336Sdfr printf("Try unionizing the nu_nickname and nu_flag fields\n"); 11259336Sdfr } 112622521Sdyson nfs_mount_type = vfsp->vfc_typenum; 11271541Srgrimes nfsrtt.pos = 0; 11281541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 11291541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 11301541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 11311541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 11321541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 11331541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 11341541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 11351541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 11369336Sdfr rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 11371541Srgrimes nfs_prog = txdr_unsigned(NFS_PROG); 11389336Sdfr nqnfs_prog = txdr_unsigned(NQNFS_PROG); 11391541Srgrimes nfs_true = txdr_unsigned(TRUE); 11401541Srgrimes nfs_false = txdr_unsigned(FALSE); 11413664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 11429336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 11439336Sdfr if (nfs_ticks < 1) 11449336Sdfr nfs_ticks = 1; 11451541Srgrimes /* Ensure async daemons disabled */ 114619449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 11471541Srgrimes nfs_iodwant[i] = (struct proc *)0; 114819449Sdfr nfs_iodmount[i] = (struct nfsmount *)0; 114919449Sdfr } 11501541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 115113416Sphk#ifndef NFS_NOSERVER 11521541Srgrimes nfsrv_init(0); /* Init server data structures */ 11531541Srgrimes nfsrv_initcache(); /* Init the server request cache */ 115413416Sphk#endif 11551541Srgrimes 11561541Srgrimes /* 11571541Srgrimes * Initialize the nqnfs server stuff. 11581541Srgrimes */ 11591541Srgrimes if (nqnfsstarttime == 0) { 11601541Srgrimes nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 11611541Srgrimes + nqsrv_clockskew + nqsrv_writeslack; 11621541Srgrimes NQLOADNOVRAM(nqnfsstarttime); 11633664Sphk CIRCLEQ_INIT(&nqtimerhead); 11643664Sphk nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 11651541Srgrimes } 11661541Srgrimes 11671541Srgrimes /* 11681541Srgrimes * Initialize reply list and start timer 11691541Srgrimes */ 11703664Sphk TAILQ_INIT(&nfs_reqq); 117116365Sphk 11723305Sphk nfs_timer(0); 11731549Srgrimes 11742997Swollman /* 11752997Swollman * Set up lease_check and lease_updatetime so that other parts 11762997Swollman * of the system can call us, if we are loadable. 11772997Swollman */ 117813416Sphk#ifndef NFS_NOSERVER 117938894Sbde nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; 118030738Sphk default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; 118113416Sphk#endif 118238894Sbde nfs_prev_lease_updatetime = lease_updatetime; 11832997Swollman lease_updatetime = nfs_lease_updatetime; 118438894Sbde nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 11852997Swollman sysent[SYS_nfssvc].sy_narg = 2; 118638894Sbde nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 118730738Sphk sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 118813416Sphk#ifndef NFS_NOSERVER 118938894Sbde nfs_prev_getfh_sy_narg = sysent[SYS_getfh].sy_narg; 11902997Swollman sysent[SYS_getfh].sy_narg = 2; 119138894Sbde nfs_prev_getfh_sy_call = sysent[SYS_getfh].sy_call; 119230738Sphk sysent[SYS_getfh].sy_call = (sy_call_t *)getfh; 11932997Swollman#endif 11942997Swollman 119542957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 119642957Sdillon 11971549Srgrimes return (0); 11981541Srgrimes} 11991541Srgrimes 120038894Sbdeint 120138894Sbdenfs_uninit(vfsp) 120238894Sbde struct vfsconf *vfsp; 120338894Sbde{ 120438894Sbde 120538894Sbde untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 120638894Sbde nfs_mount_type = -1; 120738894Sbde#ifndef NFS_NOSERVER 120838894Sbde default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; 120938894Sbde#endif 121038894Sbde lease_updatetime = nfs_prev_lease_updatetime; 121138894Sbde sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 121238894Sbde sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 121338894Sbde#ifndef NFS_NOSERVER 121438894Sbde sysent[SYS_getfh].sy_narg = nfs_prev_getfh_sy_narg; 121538894Sbde sysent[SYS_getfh].sy_call = nfs_prev_getfh_sy_call; 121638894Sbde#endif 121738894Sbde return (0); 121838894Sbde} 121938894Sbde 12201541Srgrimes/* 12211541Srgrimes * Attribute cache routines. 12221541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 12231541Srgrimes * that are on the mbuf list 12241541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 12251541Srgrimes * error otherwise 12261541Srgrimes */ 12271541Srgrimes 12281541Srgrimes/* 12291541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 12301541Srgrimes * the values on the mbuf list and 12311541Srgrimes * Iff vap not NULL 12321541Srgrimes * copy the attributes to *vaper 12331541Srgrimes */ 12341549Srgrimesint 12351541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper) 12361541Srgrimes struct vnode **vpp; 12371541Srgrimes struct mbuf **mdp; 12381541Srgrimes caddr_t *dposp; 12391541Srgrimes struct vattr *vaper; 12401541Srgrimes{ 12411541Srgrimes register struct vnode *vp = *vpp; 12421541Srgrimes register struct vattr *vap; 12439336Sdfr register struct nfs_fattr *fp; 12443664Sphk register struct nfsnode *np; 124536541Speter register int32_t t1; 12469336Sdfr caddr_t cp2; 12479336Sdfr int error = 0, rdev; 12481541Srgrimes struct mbuf *md; 12491541Srgrimes enum vtype vtyp; 12501541Srgrimes u_short vmode; 12511541Srgrimes struct timespec mtime; 12521541Srgrimes struct vnode *nvp; 12539336Sdfr int v3 = NFS_ISV3(vp); 12541541Srgrimes 12551541Srgrimes md = *mdp; 12569336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 125743305Sdillon if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) 12581541Srgrimes return (error); 12599336Sdfr fp = (struct nfs_fattr *)cp2; 12609336Sdfr if (v3) { 12619336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 12629336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 126347028Sphk rdev = umakedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 126416634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 12659336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 12661541Srgrimes } else { 12679336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 12689336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 12699336Sdfr /* 12709336Sdfr * XXX 12719336Sdfr * 12729336Sdfr * The duplicate information returned in fa_type and fa_mode 12739336Sdfr * is an ambiguity in the NFS version 2 protocol. 12749336Sdfr * 12759336Sdfr * VREG should be taken literally as a regular file. If a 12769336Sdfr * server intents to return some type information differently 12779336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 12789336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 12799336Sdfr * leave the examination of the mode bits even in the VREG 12809336Sdfr * case to avoid breakage for bogus servers, but we make sure 12819336Sdfr * that there are actually type bits set in the upper part of 12829336Sdfr * fa_mode (and failing that, trust the va_type field). 12839336Sdfr * 12849336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 12859336Sdfr * contain any type information (while also introduing sockets 12869336Sdfr * and FIFOs for fa_type). 12879336Sdfr */ 12889336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 12899336Sdfr vtyp = IFTOVT(vmode); 129036541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 12919336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 12929336Sdfr 12939336Sdfr /* 12949336Sdfr * Really ugly NFSv2 kludge. 12959336Sdfr */ 12969336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 12979336Sdfr vtyp = VFIFO; 12981541Srgrimes } 12999336Sdfr 13001541Srgrimes /* 13011541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 13028876Srgrimes * n_mtime fields. Check to see if it represents a special 13031541Srgrimes * device, and if so, check for a possible alias. Once the 13041541Srgrimes * correct vnode has been obtained, fill in the rest of the 13051541Srgrimes * information. 13061541Srgrimes */ 13071541Srgrimes np = VTONFS(vp); 130810219Sdfr if (vp->v_type != vtyp) { 13099336Sdfr vp->v_type = vtyp; 13101541Srgrimes if (vp->v_type == VFIFO) { 13111541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 13121541Srgrimes } 13131541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 13141541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 131547028Sphk nvp = checkalias(vp, rdev, vp->v_mount); 13163305Sphk if (nvp) { 13171541Srgrimes /* 13181541Srgrimes * Discard unneeded vnode, but save its nfsnode. 131922521Sdyson * Since the nfsnode does not have a lock, its 132022521Sdyson * vnode lock has to be carried over. 13211541Srgrimes */ 132222521Sdyson nvp->v_vnlock = vp->v_vnlock; 132322521Sdyson vp->v_vnlock = NULL; 13241541Srgrimes nvp->v_data = vp->v_data; 13251541Srgrimes vp->v_data = NULL; 13261541Srgrimes vp->v_op = spec_vnodeop_p; 13271541Srgrimes vrele(vp); 13281541Srgrimes vgone(vp); 13291541Srgrimes /* 13301541Srgrimes * Reinitialize aliased node. 13311541Srgrimes */ 13321541Srgrimes np->n_vnode = nvp; 13331541Srgrimes *vpp = vp = nvp; 13341541Srgrimes } 13351541Srgrimes } 133618397Snate np->n_mtime = mtime.tv_sec; 13371541Srgrimes } 13381541Srgrimes vap = &np->n_vattr; 13391541Srgrimes vap->va_type = vtyp; 13401541Srgrimes vap->va_mode = (vmode & 07777); 134147028Sphk vap->va_rdev = rdev; 13421541Srgrimes vap->va_mtime = mtime; 13431541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 13449336Sdfr if (v3) { 13459336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 13469336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 13479336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 134847751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 13499336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 135047751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 135136541Speter vap->va_fileid = fxdr_unsigned(int32_t, 135236541Speter fp->fa3_fileid.nfsuquad[1]); 13539336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 13549336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 13559336Sdfr vap->va_flags = 0; 13569336Sdfr vap->va_filerev = 0; 13571541Srgrimes } else { 13589336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 13599336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 13609336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 136136541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 136236541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 136347751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 136436541Speter * NFS_FABLKSIZE; 136536541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 13669336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 13671541Srgrimes vap->va_flags = 0; 136836541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 136936541Speter fp->fa2_ctime.nfsv2_sec); 137018397Snate vap->va_ctime.tv_nsec = 0; 137136541Speter vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 13721541Srgrimes vap->va_filerev = 0; 13731541Srgrimes } 13741541Srgrimes if (vap->va_size != np->n_size) { 13751541Srgrimes if (vap->va_type == VREG) { 13761541Srgrimes if (np->n_flag & NMODIFIED) { 13771541Srgrimes if (vap->va_size < np->n_size) 13781541Srgrimes vap->va_size = np->n_size; 13791541Srgrimes else 13801541Srgrimes np->n_size = vap->va_size; 13811541Srgrimes } else 13821541Srgrimes np->n_size = vap->va_size; 138341026Speter vnode_pager_setsize(vp, np->n_size); 13841541Srgrimes } else 13851541Srgrimes np->n_size = vap->va_size; 13861541Srgrimes } 138734961Sphk np->n_attrstamp = time_second; 13881541Srgrimes if (vaper != NULL) { 13891541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 13901541Srgrimes if (np->n_flag & NCHG) { 13919336Sdfr if (np->n_flag & NACC) 13929336Sdfr vaper->va_atime = np->n_atim; 13939336Sdfr if (np->n_flag & NUPD) 13949336Sdfr vaper->va_mtime = np->n_mtim; 13951541Srgrimes } 13961541Srgrimes } 13971541Srgrimes return (0); 13981541Srgrimes} 13991541Srgrimes 140036176Speter#ifdef NFS_ACDEBUG 140136176Speter#include <sys/sysctl.h> 140244101SbdeSYSCTL_DECL(_vfs_nfs); 140336176Speterstatic int nfs_acdebug; 140436176SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 140536176Speter#endif 140636176Speter 14071541Srgrimes/* 14081541Srgrimes * Check the time stamp 14091541Srgrimes * If the cache is valid, copy contents to *vap and return 0 14101541Srgrimes * otherwise return an error 14111541Srgrimes */ 14121549Srgrimesint 14131541Srgrimesnfs_getattrcache(vp, vaper) 14141541Srgrimes register struct vnode *vp; 14151541Srgrimes struct vattr *vaper; 14161541Srgrimes{ 141736176Speter register struct nfsnode *np; 14181541Srgrimes register struct vattr *vap; 141936176Speter struct nfsmount *nmp; 142036176Speter int timeo; 14211541Srgrimes 142236176Speter np = VTONFS(vp); 142336176Speter vap = &np->n_vattr; 142436176Speter nmp = VFSTONFS(vp->v_mount); 142536176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 142636176Speter timeo = (time_second - np->n_mtime) / 10; 142736176Speter 142836176Speter#ifdef NFS_ACDEBUG 142936176Speter if (nfs_acdebug>1) 143036176Speter printf("nfs_getattrcache: initial timeo = %d\n", timeo); 143136176Speter#endif 143236176Speter 143336176Speter if (vap->va_type == VDIR) { 143436176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 143536176Speter timeo = nmp->nm_acdirmin; 143636176Speter else if (timeo > nmp->nm_acdirmax) 143736176Speter timeo = nmp->nm_acdirmax; 143836176Speter } else { 143936176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 144036176Speter timeo = nmp->nm_acregmin; 144136176Speter else if (timeo > nmp->nm_acregmax) 144236176Speter timeo = nmp->nm_acregmax; 144336176Speter } 144436176Speter 144536176Speter#ifdef NFS_ACDEBUG 144636176Speter if (nfs_acdebug > 2) 144736176Speter printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 144836176Speter nmp->nm_acregmin, nmp->nm_acregmax, 144936176Speter nmp->nm_acdirmin, nmp->nm_acdirmax); 145036176Speter 145136176Speter if (nfs_acdebug) 145237089Sbde printf("nfs_getattrcache: age = %d; final timeo = %d\n", 145336176Speter (time_second - np->n_attrstamp), timeo); 145436176Speter#endif 145536176Speter 145636176Speter if ((time_second - np->n_attrstamp) >= timeo) { 14571541Srgrimes nfsstats.attrcache_misses++; 14581541Srgrimes return (ENOENT); 14591541Srgrimes } 14601541Srgrimes nfsstats.attrcache_hits++; 14611541Srgrimes if (vap->va_size != np->n_size) { 14621541Srgrimes if (vap->va_type == VREG) { 14631541Srgrimes if (np->n_flag & NMODIFIED) { 14641541Srgrimes if (vap->va_size < np->n_size) 14651541Srgrimes vap->va_size = np->n_size; 14661541Srgrimes else 14671541Srgrimes np->n_size = vap->va_size; 14681541Srgrimes } else 14691541Srgrimes np->n_size = vap->va_size; 147041026Speter vnode_pager_setsize(vp, np->n_size); 14711541Srgrimes } else 14721541Srgrimes np->n_size = vap->va_size; 14731541Srgrimes } 14741541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 14751541Srgrimes if (np->n_flag & NCHG) { 14769336Sdfr if (np->n_flag & NACC) 14779336Sdfr vaper->va_atime = np->n_atim; 14789336Sdfr if (np->n_flag & NUPD) 14799336Sdfr vaper->va_mtime = np->n_mtim; 14801541Srgrimes } 14811541Srgrimes return (0); 14821541Srgrimes} 14831541Srgrimes 148413416Sphk#ifndef NFS_NOSERVER 14851541Srgrimes/* 148627446Sdfr * Set up nameidata for a lookup() call and do it. 148727446Sdfr * 148827446Sdfr * If pubflag is set, this call is done for a lookup operation on the 148927446Sdfr * public filehandle. In that case we allow crossing mountpoints and 149027446Sdfr * absolute pathnames. However, the caller is expected to check that 149127446Sdfr * the lookup result is within the public fs, and deny access if 149227446Sdfr * it is not. 149348125Sjulian * 149448125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 149548125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 149648125Sjulian * error occurs but the parent was not requested. 149748125Sjulian * 149848125Sjulian * dirp may be set whether an error is returned or not, and must be 149948125Sjulian * released by the caller. 15001541Srgrimes */ 15011549Srgrimesint 150227446Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 15031541Srgrimes register struct nameidata *ndp; 15041541Srgrimes fhandle_t *fhp; 15051541Srgrimes int len; 15061541Srgrimes struct nfssvc_sock *slp; 150728270Swollman struct sockaddr *nam; 15081541Srgrimes struct mbuf **mdp; 15091541Srgrimes caddr_t *dposp; 15109336Sdfr struct vnode **retdirp; 15111541Srgrimes struct proc *p; 151227446Sdfr int kerbflag, pubflag; 15131541Srgrimes{ 15141541Srgrimes register int i, rem; 15151541Srgrimes register struct mbuf *md; 151627446Sdfr register char *fromcp, *tocp, *cp; 151727446Sdfr struct iovec aiov; 151827446Sdfr struct uio auio; 15191541Srgrimes struct vnode *dp; 152027446Sdfr int error, rdonly, linklen; 15211541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 15221541Srgrimes 15239336Sdfr *retdirp = (struct vnode *)0; 152429653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 152529653Sdyson 15261541Srgrimes /* 15271541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 15281541Srgrimes * and set the various ndp fields appropriately. 15291541Srgrimes */ 15301541Srgrimes fromcp = *dposp; 15311541Srgrimes tocp = cnp->cn_pnbuf; 15321541Srgrimes md = *mdp; 15331541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 15341541Srgrimes cnp->cn_hash = 0; 15351541Srgrimes for (i = 0; i < len; i++) { 15361541Srgrimes while (rem == 0) { 15371541Srgrimes md = md->m_next; 15381541Srgrimes if (md == NULL) { 15391541Srgrimes error = EBADRPC; 15401541Srgrimes goto out; 15411541Srgrimes } 15421541Srgrimes fromcp = mtod(md, caddr_t); 15431541Srgrimes rem = md->m_len; 15441541Srgrimes } 154527446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 15469336Sdfr error = EACCES; 15471541Srgrimes goto out; 15481541Srgrimes } 15491541Srgrimes cnp->cn_hash += (unsigned char)*fromcp; 15501541Srgrimes *tocp++ = *fromcp++; 15511541Srgrimes rem--; 15521541Srgrimes } 15531541Srgrimes *tocp = '\0'; 15541541Srgrimes *mdp = md; 15551541Srgrimes *dposp = fromcp; 15561541Srgrimes len = nfsm_rndup(len)-len; 15571541Srgrimes if (len > 0) { 15581541Srgrimes if (rem >= len) 15591541Srgrimes *dposp += len; 156027609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 15619336Sdfr goto out; 15621541Srgrimes } 156327446Sdfr 15641541Srgrimes /* 15651541Srgrimes * Extract and set starting directory. 15661541Srgrimes */ 156727446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 156827446Sdfr nam, &rdonly, kerbflag, pubflag); 156927446Sdfr if (error) 15701541Srgrimes goto out; 15711541Srgrimes if (dp->v_type != VDIR) { 157217761Sdyson vrele(dp); 15731541Srgrimes error = ENOTDIR; 15741541Srgrimes goto out; 15751541Srgrimes } 157627446Sdfr 157727446Sdfr if (rdonly) 157827446Sdfr cnp->cn_flags |= RDONLY; 157927446Sdfr 158048125Sjulian /* 158148125Sjulian * Set return directory. Reference to dp is implicitly transfered 158248125Sjulian * to the returned pointer 158348125Sjulian */ 158427609Sdfr *retdirp = dp; 158527609Sdfr 158627446Sdfr if (pubflag) { 158727446Sdfr /* 158827446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 158927446Sdfr * and the 'native path' indicator. 159027446Sdfr */ 159129653Sdyson cp = zalloc(namei_zone); 159227446Sdfr fromcp = cnp->cn_pnbuf; 159327446Sdfr tocp = cp; 159427446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 159527446Sdfr switch ((unsigned char)*fromcp) { 159627446Sdfr case WEBNFS_NATIVE_CHAR: 159727446Sdfr /* 159827446Sdfr * 'Native' path for us is the same 159927446Sdfr * as a path according to the NFS spec, 160027446Sdfr * just skip the escape char. 160127446Sdfr */ 160227446Sdfr fromcp++; 160327446Sdfr break; 160427446Sdfr /* 160527446Sdfr * More may be added in the future, range 0x80-0xff 160627446Sdfr */ 160727446Sdfr default: 160827446Sdfr error = EIO; 160929653Sdyson zfree(namei_zone, cp); 161027446Sdfr goto out; 161127446Sdfr } 161227446Sdfr } 161327446Sdfr /* 161427446Sdfr * Translate the '%' escapes, URL-style. 161527446Sdfr */ 161627446Sdfr while (*fromcp != '\0') { 161727446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 161827446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 161927446Sdfr fromcp++; 162027446Sdfr *tocp++ = HEXSTRTOI(fromcp); 162127446Sdfr fromcp += 2; 162227446Sdfr continue; 162327446Sdfr } else { 162427446Sdfr error = ENOENT; 162529653Sdyson zfree(namei_zone, cp); 162627446Sdfr goto out; 162727446Sdfr } 162827446Sdfr } else 162927446Sdfr *tocp++ = *fromcp++; 163027446Sdfr } 163127446Sdfr *tocp = '\0'; 163229653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 163327446Sdfr cnp->cn_pnbuf = cp; 163427446Sdfr } 163527446Sdfr 163627446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 163727446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 163827446Sdfr 163927446Sdfr if (pubflag) { 164027446Sdfr ndp->ni_rootdir = rootvnode; 164127446Sdfr ndp->ni_loopcnt = 0; 164227446Sdfr if (cnp->cn_pnbuf[0] == '/') 164327446Sdfr dp = rootvnode; 164427446Sdfr } else { 164527609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 164627446Sdfr } 164727446Sdfr 164848125Sjulian /* 164948125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 165048125Sjulian * becuase lookup() will dereference ni_startdir. 165148125Sjulian */ 165248125Sjulian 165327446Sdfr cnp->cn_proc = p; 16549336Sdfr VREF(dp); 165548125Sjulian ndp->ni_startdir = dp; 165627446Sdfr 165748125Sjulian for (;;) { 165848125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 165948125Sjulian /* 166048125Sjulian * Call lookup() to do the real work. If an error occurs, 166148125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 166248125Sjulian * we do not have to dereference anything before returning. 166348125Sjulian * In either case ni_startdir will be dereferenced and NULLed 166448125Sjulian * out. 166548125Sjulian */ 166648125Sjulian error = lookup(ndp); 166748125Sjulian if (error) 166848125Sjulian break; 166948125Sjulian 167048125Sjulian /* 167148125Sjulian * Check for encountering a symbolic link. Trivial 167248125Sjulian * termination occurs if no symlink encountered. 167348125Sjulian * Note: zfree is safe because error is 0, so we will 167448125Sjulian * not zfree it again when we break. 167548125Sjulian */ 167648125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 167748125Sjulian nfsrv_object_create(ndp->ni_vp); 167848125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 167948125Sjulian cnp->cn_flags |= HASBUF; 168048125Sjulian else 168148125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 168248125Sjulian break; 168327446Sdfr } 168448125Sjulian 168548125Sjulian /* 168648125Sjulian * Validate symlink 168748125Sjulian */ 16881541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 168927446Sdfr VOP_UNLOCK(ndp->ni_dvp, 0, p); 169027446Sdfr if (!pubflag) { 169127446Sdfr error = EINVAL; 169248125Sjulian goto badlink2; 169327446Sdfr } 169427446Sdfr 169527446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 169627446Sdfr error = ELOOP; 169748125Sjulian goto badlink2; 169827446Sdfr } 169927609Sdfr if (ndp->ni_pathlen > 1) 170029653Sdyson cp = zalloc(namei_zone); 17011541Srgrimes else 170227446Sdfr cp = cnp->cn_pnbuf; 170327446Sdfr aiov.iov_base = cp; 170427446Sdfr aiov.iov_len = MAXPATHLEN; 170527446Sdfr auio.uio_iov = &aiov; 170627446Sdfr auio.uio_iovcnt = 1; 170727446Sdfr auio.uio_offset = 0; 170827446Sdfr auio.uio_rw = UIO_READ; 170927446Sdfr auio.uio_segflg = UIO_SYSSPACE; 171027446Sdfr auio.uio_procp = (struct proc *)0; 171127446Sdfr auio.uio_resid = MAXPATHLEN; 171227446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 171327446Sdfr if (error) { 171448125Sjulian badlink1: 171527446Sdfr if (ndp->ni_pathlen > 1) 171629653Sdyson zfree(namei_zone, cp); 171748125Sjulian badlink2: 171848125Sjulian vrele(ndp->ni_dvp); 171948125Sjulian vput(ndp->ni_vp); 172027446Sdfr break; 172127446Sdfr } 172227446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 172327446Sdfr if (linklen == 0) { 172427446Sdfr error = ENOENT; 172548125Sjulian goto badlink1; 172627446Sdfr } 172727446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 172827446Sdfr error = ENAMETOOLONG; 172948125Sjulian goto badlink1; 173027446Sdfr } 173148125Sjulian 173248125Sjulian /* 173348125Sjulian * Adjust or replace path 173448125Sjulian */ 173527446Sdfr if (ndp->ni_pathlen > 1) { 173627446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 173729653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 173827446Sdfr cnp->cn_pnbuf = cp; 173927446Sdfr } else 174027446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 174127446Sdfr ndp->ni_pathlen += linklen; 174248125Sjulian 174327446Sdfr /* 174448125Sjulian * Cleanup refs for next loop and check if root directory 174548125Sjulian * should replace current directory. Normally ni_dvp 174648125Sjulian * becomes the new base directory and is cleaned up when 174748125Sjulian * we loop. Explicitly null pointers after invalidation 174848125Sjulian * to clarify operation. 174927446Sdfr */ 175048125Sjulian vput(ndp->ni_vp); 175148125Sjulian ndp->ni_vp = NULL; 175248125Sjulian 175327446Sdfr if (cnp->cn_pnbuf[0] == '/') { 175448125Sjulian vrele(ndp->ni_dvp); 175548125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 175648125Sjulian VREF(ndp->ni_dvp); 175727446Sdfr } 175848125Sjulian ndp->ni_startdir = ndp->ni_dvp; 175948125Sjulian ndp->ni_dvp = NULL; 17601541Srgrimes } 176148125Sjulian 176248125Sjulian /* 176348125Sjulian * nfs_namei() guarentees that fields will not contain garbage 176448125Sjulian * whether an error occurs or not. This allows the caller to track 176548125Sjulian * cleanup state trivially. 176648125Sjulian */ 17671541Srgrimesout: 176848125Sjulian if (error) { 176948125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 177048125Sjulian ndp->ni_vp = NULL; 177148125Sjulian ndp->ni_dvp = NULL; 177248125Sjulian ndp->ni_startdir = NULL; 177348125Sjulian cnp->cn_flags &= ~HASBUF; 177448125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 177548125Sjulian ndp->ni_dvp = NULL; 177648125Sjulian } 17771541Srgrimes return (error); 17781541Srgrimes} 17791541Srgrimes 17801541Srgrimes/* 17811541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 17821541Srgrimes * boundary and only trims off the back end 17831541Srgrimes */ 17841541Srgrimesvoid 17851541Srgrimesnfsm_adj(mp, len, nul) 17861541Srgrimes struct mbuf *mp; 17871541Srgrimes register int len; 17881541Srgrimes int nul; 17891541Srgrimes{ 17901541Srgrimes register struct mbuf *m; 17911541Srgrimes register int count, i; 17921541Srgrimes register char *cp; 17931541Srgrimes 17941541Srgrimes /* 17951541Srgrimes * Trim from tail. Scan the mbuf chain, 17961541Srgrimes * calculating its length and finding the last mbuf. 17971541Srgrimes * If the adjustment only affects this mbuf, then just 17981541Srgrimes * adjust and return. Otherwise, rescan and truncate 17991541Srgrimes * after the remaining size. 18001541Srgrimes */ 18011541Srgrimes count = 0; 18021541Srgrimes m = mp; 18031541Srgrimes for (;;) { 18041541Srgrimes count += m->m_len; 18051541Srgrimes if (m->m_next == (struct mbuf *)0) 18061541Srgrimes break; 18071541Srgrimes m = m->m_next; 18081541Srgrimes } 18091541Srgrimes if (m->m_len > len) { 18101541Srgrimes m->m_len -= len; 18111541Srgrimes if (nul > 0) { 18121541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 18131541Srgrimes for (i = 0; i < nul; i++) 18141541Srgrimes *cp++ = '\0'; 18151541Srgrimes } 18161541Srgrimes return; 18171541Srgrimes } 18181541Srgrimes count -= len; 18191541Srgrimes if (count < 0) 18201541Srgrimes count = 0; 18211541Srgrimes /* 18221541Srgrimes * Correct length for chain is "count". 18231541Srgrimes * Find the mbuf with last data, adjust its length, 18241541Srgrimes * and toss data from remaining mbufs on chain. 18251541Srgrimes */ 18261541Srgrimes for (m = mp; m; m = m->m_next) { 18271541Srgrimes if (m->m_len >= count) { 18281541Srgrimes m->m_len = count; 18291541Srgrimes if (nul > 0) { 18301541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 18311541Srgrimes for (i = 0; i < nul; i++) 18321541Srgrimes *cp++ = '\0'; 18331541Srgrimes } 18341541Srgrimes break; 18351541Srgrimes } 18361541Srgrimes count -= m->m_len; 18371541Srgrimes } 18383305Sphk for (m = m->m_next;m;m = m->m_next) 18391541Srgrimes m->m_len = 0; 18401541Srgrimes} 18411541Srgrimes 18421541Srgrimes/* 18439336Sdfr * Make these functions instead of macros, so that the kernel text size 18449336Sdfr * doesn't get too big... 18459336Sdfr */ 18469336Sdfrvoid 18479336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 18489336Sdfr struct nfsrv_descript *nfsd; 18499336Sdfr int before_ret; 18509336Sdfr register struct vattr *before_vap; 18519336Sdfr int after_ret; 18529336Sdfr struct vattr *after_vap; 18539336Sdfr struct mbuf **mbp; 18549336Sdfr char **bposp; 18559336Sdfr{ 18569336Sdfr register struct mbuf *mb = *mbp, *mb2; 18579336Sdfr register char *bpos = *bposp; 185836541Speter register u_int32_t *tl; 18599336Sdfr 18609336Sdfr if (before_ret) { 186136541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 18629336Sdfr *tl = nfs_false; 18639336Sdfr } else { 186436541Speter nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 18659336Sdfr *tl++ = nfs_true; 186647751Speter txdr_hyper(before_vap->va_size, tl); 18679336Sdfr tl += 2; 18689336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 18699336Sdfr tl += 2; 18709336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 18719336Sdfr } 18729336Sdfr *bposp = bpos; 18739336Sdfr *mbp = mb; 18749336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 18759336Sdfr} 18769336Sdfr 18779336Sdfrvoid 18789336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 18799336Sdfr struct nfsrv_descript *nfsd; 18809336Sdfr int after_ret; 18819336Sdfr struct vattr *after_vap; 18829336Sdfr struct mbuf **mbp; 18839336Sdfr char **bposp; 18849336Sdfr{ 18859336Sdfr register struct mbuf *mb = *mbp, *mb2; 18869336Sdfr register char *bpos = *bposp; 188736541Speter register u_int32_t *tl; 18889336Sdfr register struct nfs_fattr *fp; 18899336Sdfr 18909336Sdfr if (after_ret) { 189136541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 18929336Sdfr *tl = nfs_false; 18939336Sdfr } else { 189436541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 18959336Sdfr *tl++ = nfs_true; 18969336Sdfr fp = (struct nfs_fattr *)tl; 18979336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 18989336Sdfr } 18999336Sdfr *mbp = mb; 19009336Sdfr *bposp = bpos; 19019336Sdfr} 19029336Sdfr 19039336Sdfrvoid 19049336Sdfrnfsm_srvfattr(nfsd, vap, fp) 19059336Sdfr register struct nfsrv_descript *nfsd; 19069336Sdfr register struct vattr *vap; 19079336Sdfr register struct nfs_fattr *fp; 19089336Sdfr{ 19099336Sdfr 19109336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 19119336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 19129336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 19139336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 19149336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 19159336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 191647751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 191747751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 191847028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 191947028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 19209336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 19219336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 19229336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 19239336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 19249336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 19259336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 19269336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 19279336Sdfr } else { 19289336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 19299336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 19309336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 19319336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 19329336Sdfr if (vap->va_type == VFIFO) 19339336Sdfr fp->fa2_rdev = 0xffffffff; 19349336Sdfr else 19359336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 19369336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 19379336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 19389336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 19399336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 19409336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 19419336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 19429336Sdfr } 19439336Sdfr} 19449336Sdfr 19459336Sdfr/* 19461541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 19471541Srgrimes * - look up fsid in mount list (if not found ret error) 19481541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 19491541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 19501541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 19511541Srgrimes */ 19521549Srgrimesint 195327446Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 19541541Srgrimes fhandle_t *fhp; 19551541Srgrimes int lockflag; 19561541Srgrimes struct vnode **vpp; 19571541Srgrimes struct ucred *cred; 19581541Srgrimes struct nfssvc_sock *slp; 195928270Swollman struct sockaddr *nam; 19601541Srgrimes int *rdonlyp; 19619336Sdfr int kerbflag; 196227446Sdfr int pubflag; 19631541Srgrimes{ 196422521Sdyson struct proc *p = curproc; /* XXX */ 19651541Srgrimes register struct mount *mp; 19661541Srgrimes register int i; 19671541Srgrimes struct ucred *credanon; 19681541Srgrimes int error, exflags; 196936534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 197036534Speter struct sockaddr_int *saddr; 197136534Speter#endif 19721541Srgrimes 19731541Srgrimes *vpp = (struct vnode *)0; 197427446Sdfr 197527446Sdfr if (nfs_ispublicfh(fhp)) { 197627446Sdfr if (!pubflag || !nfs_pub.np_valid) 197727446Sdfr return (ESTALE); 197827446Sdfr fhp = &nfs_pub.np_handle; 197927446Sdfr } 198027446Sdfr 198122521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 19823305Sphk if (!mp) 19831541Srgrimes return (ESTALE); 19843305Sphk error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 19853305Sphk if (error) 19861541Srgrimes return (error); 198736534Speter#ifdef MNT_EXNORESPORT 198836534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 198936534Speter saddr = (struct sockaddr_in *)nam; 199036534Speter if (saddr->sin_family == AF_INET && 199136534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 199236534Speter vput(*vpp); 199336534Speter return (NFSERR_AUTHERR | AUTH_TOOWEAK); 199436534Speter } 199536534Speter } 199636534Speter#endif 19971541Srgrimes /* 19981541Srgrimes * Check/setup credentials. 19991541Srgrimes */ 20001541Srgrimes if (exflags & MNT_EXKERB) { 20019336Sdfr if (!kerbflag) { 20021541Srgrimes vput(*vpp); 20039336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 20041541Srgrimes } 20059336Sdfr } else if (kerbflag) { 20069336Sdfr vput(*vpp); 20079336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 20081541Srgrimes } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 20091541Srgrimes cred->cr_uid = credanon->cr_uid; 20101541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 20111541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 20123664Sphk cred->cr_ngroups = i; 20131541Srgrimes } 20141541Srgrimes if (exflags & MNT_EXRDONLY) 20151541Srgrimes *rdonlyp = 1; 20161541Srgrimes else 20171541Srgrimes *rdonlyp = 0; 20187969Sdyson 201917761Sdyson nfsrv_object_create(*vpp); 20207969Sdyson 20211541Srgrimes if (!lockflag) 202222521Sdyson VOP_UNLOCK(*vpp, 0, p); 20231541Srgrimes return (0); 20241541Srgrimes} 20251541Srgrimes 202627446Sdfr 202727446Sdfr/* 202827446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 202927446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 203027446Sdfr * transformed this to all zeroes in both cases, so check for it. 203127446Sdfr */ 203227446Sdfrint 203327446Sdfrnfs_ispublicfh(fhp) 203427446Sdfr fhandle_t *fhp; 203527446Sdfr{ 203627446Sdfr char *cp = (char *)fhp; 203727446Sdfr int i; 203827446Sdfr 203927446Sdfr for (i = 0; i < NFSX_V3FH; i++) 204027446Sdfr if (*cp++ != 0) 204127446Sdfr return (FALSE); 204227446Sdfr return (TRUE); 204327446Sdfr} 204427446Sdfr 204513416Sphk#endif /* NFS_NOSERVER */ 20461541Srgrimes/* 20471541Srgrimes * This function compares two net addresses by family and returns TRUE 20481541Srgrimes * if they are the same host. 20491541Srgrimes * If there is any doubt, return FALSE. 20501541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 20511541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 20521541Srgrimes */ 20531549Srgrimesint 20541541Srgrimesnetaddr_match(family, haddr, nam) 20551541Srgrimes int family; 20561541Srgrimes union nethostaddr *haddr; 205728270Swollman struct sockaddr *nam; 20581541Srgrimes{ 20591541Srgrimes register struct sockaddr_in *inetaddr; 20601541Srgrimes 20611541Srgrimes switch (family) { 20621541Srgrimes case AF_INET: 206328270Swollman inetaddr = (struct sockaddr_in *)nam; 20641541Srgrimes if (inetaddr->sin_family == AF_INET && 20651541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 20661541Srgrimes return (1); 20671541Srgrimes break; 20681541Srgrimes#ifdef ISO 20691541Srgrimes case AF_ISO: 20701541Srgrimes { 20711541Srgrimes register struct sockaddr_iso *isoaddr1, *isoaddr2; 20721541Srgrimes 207328270Swollman isoaddr1 = (struct sockaddr_iso *)nam; 207428270Swollman isoaddr2 = (struct sockaddr_iso *)haddr->had_nam; 20751541Srgrimes if (isoaddr1->siso_family == AF_ISO && 20761541Srgrimes isoaddr1->siso_nlen > 0 && 20771541Srgrimes isoaddr1->siso_nlen == isoaddr2->siso_nlen && 20781541Srgrimes SAME_ISOADDR(isoaddr1, isoaddr2)) 20791541Srgrimes return (1); 20801541Srgrimes break; 20811541Srgrimes } 20821541Srgrimes#endif /* ISO */ 20831541Srgrimes default: 20841541Srgrimes break; 20851541Srgrimes }; 20861541Srgrimes return (0); 20871541Srgrimes} 20885455Sdg 208943305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 20909336Sdfr/* 20919336Sdfr * This function finds the directory cookie that corresponds to the 20929336Sdfr * logical byte offset given. 20939336Sdfr */ 20949336Sdfrnfsuint64 * 20959336Sdfrnfs_getcookie(np, off, add) 20969336Sdfr register struct nfsnode *np; 20979336Sdfr off_t off; 20989336Sdfr int add; 20999336Sdfr{ 21009336Sdfr register struct nfsdmap *dp, *dp2; 21019336Sdfr register int pos; 21029336Sdfr 210336979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 210436979Sbde if (pos == 0 || off < 0) { 21059336Sdfr#ifdef DIAGNOSTIC 21069336Sdfr if (add) 210736979Sbde panic("nfs getcookie add at <= 0"); 21089336Sdfr#endif 21099336Sdfr return (&nfs_nullcookie); 21109336Sdfr } 21119336Sdfr pos--; 21129336Sdfr dp = np->n_cookies.lh_first; 21139336Sdfr if (!dp) { 21149336Sdfr if (add) { 21159336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 21169336Sdfr M_NFSDIROFF, M_WAITOK); 21179336Sdfr dp->ndm_eocookie = 0; 21189336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 21199336Sdfr } else 21209336Sdfr return ((nfsuint64 *)0); 21219336Sdfr } 21229336Sdfr while (pos >= NFSNUMCOOKIES) { 21239336Sdfr pos -= NFSNUMCOOKIES; 21249336Sdfr if (dp->ndm_list.le_next) { 21259336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 21269336Sdfr pos >= dp->ndm_eocookie) 21279336Sdfr return ((nfsuint64 *)0); 21289336Sdfr dp = dp->ndm_list.le_next; 21299336Sdfr } else if (add) { 21309336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 21319336Sdfr M_NFSDIROFF, M_WAITOK); 21329336Sdfr dp2->ndm_eocookie = 0; 21339336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 21349336Sdfr dp = dp2; 21359336Sdfr } else 21369336Sdfr return ((nfsuint64 *)0); 21379336Sdfr } 21389336Sdfr if (pos >= dp->ndm_eocookie) { 21399336Sdfr if (add) 21409336Sdfr dp->ndm_eocookie = pos + 1; 21419336Sdfr else 21429336Sdfr return ((nfsuint64 *)0); 21439336Sdfr } 21449336Sdfr return (&dp->ndm_cookies[pos]); 21459336Sdfr} 21469336Sdfr 21479336Sdfr/* 21489336Sdfr * Invalidate cached directory information, except for the actual directory 21499336Sdfr * blocks (which are invalidated separately). 21509336Sdfr * Done mainly to avoid the use of stale offset cookies. 21519336Sdfr */ 21529336Sdfrvoid 21539336Sdfrnfs_invaldir(vp) 21549336Sdfr register struct vnode *vp; 21559336Sdfr{ 21569336Sdfr register struct nfsnode *np = VTONFS(vp); 21579336Sdfr 21589336Sdfr#ifdef DIAGNOSTIC 21599336Sdfr if (vp->v_type != VDIR) 21609336Sdfr panic("nfs: invaldir not dir"); 21619336Sdfr#endif 21629336Sdfr np->n_direofoffset = 0; 21639336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 21649336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 21659336Sdfr if (np->n_cookies.lh_first) 21669336Sdfr np->n_cookies.lh_first->ndm_eocookie = 0; 21679336Sdfr} 21689336Sdfr 21699336Sdfr/* 21709336Sdfr * The write verifier has changed (probably due to a server reboot), so all 21719336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 21729336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 21739336Sdfr * flag. Once done the new write verifier can be set for the mount point. 21749336Sdfr */ 21759336Sdfrvoid 21769336Sdfrnfs_clearcommit(mp) 21779336Sdfr struct mount *mp; 21789336Sdfr{ 21799336Sdfr register struct vnode *vp, *nvp; 21809336Sdfr register struct buf *bp, *nbp; 21819336Sdfr int s; 21829336Sdfr 21839336Sdfr s = splbio(); 21849336Sdfrloop: 21859336Sdfr for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 21869336Sdfr if (vp->v_mount != mp) /* Paranoia */ 21879336Sdfr goto loop; 21889336Sdfr nvp = vp->v_mntvnodes.le_next; 218940790Speter for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 219040790Speter nbp = TAILQ_NEXT(bp, b_vnbufs); 219148225Smckusick if (BUF_REFCNT(bp) == 0 && 219248225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 21939336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 21949336Sdfr bp->b_flags &= ~B_NEEDCOMMIT; 21959336Sdfr } 21969336Sdfr } 21979336Sdfr splx(s); 21989336Sdfr} 21999336Sdfr 220013416Sphk#ifndef NFS_NOSERVER 22019336Sdfr/* 22029336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 22039336Sdfr * numbers not specified for the associated procedure. 22049336Sdfr */ 22055455Sdgint 22069336Sdfrnfsrv_errmap(nd, err) 22079336Sdfr struct nfsrv_descript *nd; 22089336Sdfr register int err; 22099336Sdfr{ 22109336Sdfr register short *defaulterrp, *errp; 22119336Sdfr 22129336Sdfr if (nd->nd_flag & ND_NFSV3) { 22139336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 22149336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 22159336Sdfr while (*++errp) { 22169336Sdfr if (*errp == err) 22179336Sdfr return (err); 22189336Sdfr else if (*errp > err) 22199336Sdfr break; 22209336Sdfr } 22219336Sdfr return ((int)*defaulterrp); 22229336Sdfr } else 22239336Sdfr return (err & 0xffff); 22249336Sdfr } 22259336Sdfr if (err <= ELAST) 22269336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 22279336Sdfr return (NFSERR_IO); 22289336Sdfr} 22299336Sdfr 22309336Sdfrint 223131886Sbdenfsrv_object_create(vp) 223231886Sbde struct vnode *vp; 223331886Sbde{ 22345455Sdg 223531886Sbde if (vp == NULL || vp->v_type != VREG) 223631886Sbde return (1); 223731886Sbde return (vfs_object_create(vp, curproc, 223842315Seivind curproc ? curproc->p_ucred : NULL)); 22395455Sdg} 224036503Speter 224136503Speter/* 224236503Speter * Sort the group list in increasing numerical order. 224336503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 224436503Speter * that used to be here.) 224536503Speter */ 224636503Spetervoid 224736503Speternfsrvw_sort(list, num) 224836503Speter register gid_t *list; 224936503Speter register int num; 225036503Speter{ 225136503Speter register int i, j; 225236503Speter gid_t v; 225336503Speter 225436503Speter /* Insertion sort. */ 225536503Speter for (i = 1; i < num; i++) { 225636503Speter v = list[i]; 225736503Speter /* find correct slot for value v, moving others up */ 225836503Speter for (j = i; --j >= 0 && v < list[j];) 225936503Speter list[j + 1] = list[j]; 226036503Speter list[j + 1] = v; 226136503Speter } 226236503Speter} 226336503Speter 226436503Speter/* 226536503Speter * copy credentials making sure that the result can be compared with bcmp(). 226636503Speter */ 226736503Spetervoid 226836503Speternfsrv_setcred(incred, outcred) 226936503Speter register struct ucred *incred, *outcred; 227036503Speter{ 227136503Speter register int i; 227236503Speter 227336503Speter bzero((caddr_t)outcred, sizeof (struct ucred)); 227436503Speter outcred->cr_ref = 1; 227536503Speter outcred->cr_uid = incred->cr_uid; 227636503Speter outcred->cr_ngroups = incred->cr_ngroups; 227736503Speter for (i = 0; i < incred->cr_ngroups; i++) 227836503Speter outcred->cr_groups[i] = incred->cr_groups[i]; 227936503Speter nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 228036503Speter} 228113416Sphk#endif /* NFS_NOSERVER */ 2282