nfs_subs.c revision 60041
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 3750477Speter * $FreeBSD: head/sys/nfsclient/nfs_subs.c 60041 2000-05-05 09:59:14Z phk $ 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> 4648274Speter#include <sys/systm.h> 4748274Speter#include <sys/kernel.h> 4860041Sphk#include <sys/bio.h> 4931886Sbde#include <sys/buf.h> 501541Srgrimes#include <sys/proc.h> 511541Srgrimes#include <sys/mount.h> 521541Srgrimes#include <sys/vnode.h> 531541Srgrimes#include <sys/namei.h> 541541Srgrimes#include <sys/mbuf.h> 551541Srgrimes#include <sys/socket.h> 561541Srgrimes#include <sys/stat.h> 579336Sdfr#include <sys/malloc.h> 582997Swollman#include <sys/sysent.h> 592997Swollman#include <sys/syscall.h> 601541Srgrimes 613305Sphk#include <vm/vm.h> 6212662Sdg#include <vm/vm_object.h> 6312662Sdg#include <vm/vm_extern.h> 6432011Sbde#include <vm/vm_zone.h> 653305Sphk 661541Srgrimes#include <nfs/rpcv2.h> 679336Sdfr#include <nfs/nfsproto.h> 6830808Sbde#include <nfs/nfs.h> 691541Srgrimes#include <nfs/nfsnode.h> 701541Srgrimes#include <nfs/xdr_subs.h> 711541Srgrimes#include <nfs/nfsm_subs.h> 721541Srgrimes#include <nfs/nfsmount.h> 731541Srgrimes#include <nfs/nqnfs.h> 741541Srgrimes#include <nfs/nfsrtt.h> 751541Srgrimes 761541Srgrimes#include <netinet/in.h> 771541Srgrimes 781541Srgrimes/* 791541Srgrimes * Data items converted to xdr at startup, since they are constant 801541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 811541Srgrimes */ 8236541Speteru_int32_t nfs_xdrneg1; 8336541Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 849336Sdfr rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 851541Srgrimes rpc_auth_kerb; 8636541Speteru_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 871541Srgrimes 881541Srgrimes/* And other global data */ 8936541Speterstatic u_int32_t nfs_xid = 0; 9012911Sphkstatic enum vtype nv2tov_type[8]= { 9112911Sphk VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9212911Sphk}; 9312911Sphkenum vtype nv3tov_type[8]= { 9412911Sphk VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 9512911Sphk}; 9612911Sphk 979336Sdfrint nfs_ticks; 9842957Sdillonint nfs_pbuf_freecnt = -1; /* start out unlimited */ 999336Sdfr 1009759Sbdestruct nfs_reqq nfs_reqq; 1019759Sbdestruct nfssvc_sockhead nfssvc_sockhead; 1029759Sbdeint nfssvc_sockhead_flag; 1039759Sbdestruct nfsd_head nfsd_head; 1049759Sbdeint nfsd_head_flag; 1059759Sbdestruct nfs_bufq nfs_bufq; 1069759Sbdestruct nqtimerhead nqtimerhead; 1079759Sbdestruct nqfhhashhead *nqfhhashtbl; 1089759Sbdeu_long nqfhhash; 1099759Sbde 11038894Sbdestatic void (*nfs_prev_lease_updatetime) __P((int)); 11138894Sbdestatic int nfs_prev_nfssvc_sy_narg; 11238894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call; 11338894Sbde 11413416Sphk#ifndef NFS_NOSERVER 11538894Sbde 11638894Sbdestatic vop_t *nfs_prev_vop_lease_check; 11738894Sbde 1189336Sdfr/* 1199336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1209336Sdfr */ 1219336Sdfrint nfsv3_procid[NFS_NPROCS] = { 1229336Sdfr NFSPROC_NULL, 1239336Sdfr NFSPROC_GETATTR, 1249336Sdfr NFSPROC_SETATTR, 1259336Sdfr NFSPROC_NOOP, 1269336Sdfr NFSPROC_LOOKUP, 1279336Sdfr NFSPROC_READLINK, 1289336Sdfr NFSPROC_READ, 1299336Sdfr NFSPROC_NOOP, 1309336Sdfr NFSPROC_WRITE, 1319336Sdfr NFSPROC_CREATE, 1329336Sdfr NFSPROC_REMOVE, 1339336Sdfr NFSPROC_RENAME, 1349336Sdfr NFSPROC_LINK, 1359336Sdfr NFSPROC_SYMLINK, 1369336Sdfr NFSPROC_MKDIR, 1379336Sdfr NFSPROC_RMDIR, 1389336Sdfr NFSPROC_READDIR, 1399336Sdfr NFSPROC_FSSTAT, 1409336Sdfr NFSPROC_NOOP, 1419336Sdfr NFSPROC_NOOP, 1429336Sdfr NFSPROC_NOOP, 1439336Sdfr NFSPROC_NOOP, 1449336Sdfr NFSPROC_NOOP, 1459336Sdfr NFSPROC_NOOP, 1469336Sdfr NFSPROC_NOOP, 1479336Sdfr NFSPROC_NOOP 1489336Sdfr}; 1499336Sdfr 15013416Sphk#endif /* NFS_NOSERVER */ 1519336Sdfr/* 1529336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1539336Sdfr */ 1549336Sdfrint nfsv2_procid[NFS_NPROCS] = { 1559336Sdfr NFSV2PROC_NULL, 1569336Sdfr NFSV2PROC_GETATTR, 1579336Sdfr NFSV2PROC_SETATTR, 1589336Sdfr NFSV2PROC_LOOKUP, 1599336Sdfr NFSV2PROC_NOOP, 1609336Sdfr NFSV2PROC_READLINK, 1619336Sdfr NFSV2PROC_READ, 1629336Sdfr NFSV2PROC_WRITE, 1639336Sdfr NFSV2PROC_CREATE, 1649336Sdfr NFSV2PROC_MKDIR, 1659336Sdfr NFSV2PROC_SYMLINK, 1669336Sdfr NFSV2PROC_CREATE, 1679336Sdfr NFSV2PROC_REMOVE, 1689336Sdfr NFSV2PROC_RMDIR, 1699336Sdfr NFSV2PROC_RENAME, 1709336Sdfr NFSV2PROC_LINK, 1719336Sdfr NFSV2PROC_READDIR, 1729336Sdfr NFSV2PROC_NOOP, 1739336Sdfr NFSV2PROC_STATFS, 1749336Sdfr NFSV2PROC_NOOP, 1759336Sdfr NFSV2PROC_NOOP, 1769336Sdfr NFSV2PROC_NOOP, 1779336Sdfr NFSV2PROC_NOOP, 1789336Sdfr NFSV2PROC_NOOP, 1799336Sdfr NFSV2PROC_NOOP, 1809336Sdfr NFSV2PROC_NOOP, 1819336Sdfr}; 1829336Sdfr 18313416Sphk#ifndef NFS_NOSERVER 1849336Sdfr/* 1859336Sdfr * Maps errno values to nfs error numbers. 1869336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1879336Sdfr * RFC 1094. 1889336Sdfr */ 1899336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1909336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1919336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1929336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1939336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 1949336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1959336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 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_IO, NFSERR_IO, NFSERR_IO, 1999336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 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, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 2039336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 2049336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 2059336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20641796Sdt NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20741796Sdt NFSERR_IO /* << Last is 86 */ 2089336Sdfr}; 2099336Sdfr 2109336Sdfr/* 2119336Sdfr * Maps errno values to nfs error numbers. 2129336Sdfr * Although it is not obvious whether or not NFS clients really care if 2139336Sdfr * a returned error value is in the specified list for the procedure, the 2149336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 2159336Sdfr * X/Open XNFS document is the only specification that defines error values 2169336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 2179336Sdfr * so I have decided to not do this for Version 2. 2189336Sdfr * The first entry is the default error return and the rest are the valid 2199336Sdfr * errors for that RPC in increasing numeric order. 2209336Sdfr */ 2219336Sdfrstatic short nfsv3err_null[] = { 2229336Sdfr 0, 2239336Sdfr 0, 2249336Sdfr}; 2259336Sdfr 2269336Sdfrstatic short nfsv3err_getattr[] = { 2279336Sdfr NFSERR_IO, 2289336Sdfr NFSERR_IO, 2299336Sdfr NFSERR_STALE, 2309336Sdfr NFSERR_BADHANDLE, 2319336Sdfr NFSERR_SERVERFAULT, 2329336Sdfr 0, 2339336Sdfr}; 2349336Sdfr 2359336Sdfrstatic short nfsv3err_setattr[] = { 2369336Sdfr NFSERR_IO, 2379336Sdfr NFSERR_PERM, 2389336Sdfr NFSERR_IO, 2399336Sdfr NFSERR_ACCES, 2409336Sdfr NFSERR_INVAL, 2419336Sdfr NFSERR_NOSPC, 2429336Sdfr NFSERR_ROFS, 2439336Sdfr NFSERR_DQUOT, 2449336Sdfr NFSERR_STALE, 2459336Sdfr NFSERR_BADHANDLE, 2469336Sdfr NFSERR_NOT_SYNC, 2479336Sdfr NFSERR_SERVERFAULT, 2489336Sdfr 0, 2499336Sdfr}; 2509336Sdfr 2519336Sdfrstatic short nfsv3err_lookup[] = { 2529336Sdfr NFSERR_IO, 2539336Sdfr NFSERR_NOENT, 2549336Sdfr NFSERR_IO, 2559336Sdfr NFSERR_ACCES, 2569336Sdfr NFSERR_NOTDIR, 2579336Sdfr NFSERR_NAMETOL, 2589336Sdfr NFSERR_STALE, 2599336Sdfr NFSERR_BADHANDLE, 2609336Sdfr NFSERR_SERVERFAULT, 2619336Sdfr 0, 2629336Sdfr}; 2639336Sdfr 2649336Sdfrstatic short nfsv3err_access[] = { 2659336Sdfr NFSERR_IO, 2669336Sdfr NFSERR_IO, 2679336Sdfr NFSERR_STALE, 2689336Sdfr NFSERR_BADHANDLE, 2699336Sdfr NFSERR_SERVERFAULT, 2709336Sdfr 0, 2719336Sdfr}; 2729336Sdfr 2739336Sdfrstatic short nfsv3err_readlink[] = { 2749336Sdfr NFSERR_IO, 2759336Sdfr NFSERR_IO, 2769336Sdfr NFSERR_ACCES, 2779336Sdfr NFSERR_INVAL, 2789336Sdfr NFSERR_STALE, 2799336Sdfr NFSERR_BADHANDLE, 2809336Sdfr NFSERR_NOTSUPP, 2819336Sdfr NFSERR_SERVERFAULT, 2829336Sdfr 0, 2839336Sdfr}; 2849336Sdfr 2859336Sdfrstatic short nfsv3err_read[] = { 2869336Sdfr NFSERR_IO, 2879336Sdfr NFSERR_IO, 2889336Sdfr NFSERR_NXIO, 2899336Sdfr NFSERR_ACCES, 2909336Sdfr NFSERR_INVAL, 2919336Sdfr NFSERR_STALE, 2929336Sdfr NFSERR_BADHANDLE, 2939336Sdfr NFSERR_SERVERFAULT, 2949336Sdfr 0, 2959336Sdfr}; 2969336Sdfr 2979336Sdfrstatic short nfsv3err_write[] = { 2989336Sdfr NFSERR_IO, 2999336Sdfr NFSERR_IO, 3009336Sdfr NFSERR_ACCES, 3019336Sdfr NFSERR_INVAL, 3029336Sdfr NFSERR_FBIG, 3039336Sdfr NFSERR_NOSPC, 3049336Sdfr NFSERR_ROFS, 3059336Sdfr NFSERR_DQUOT, 3069336Sdfr NFSERR_STALE, 3079336Sdfr NFSERR_BADHANDLE, 3089336Sdfr NFSERR_SERVERFAULT, 3099336Sdfr 0, 3109336Sdfr}; 3119336Sdfr 3129336Sdfrstatic short nfsv3err_create[] = { 3139336Sdfr NFSERR_IO, 3149336Sdfr NFSERR_IO, 3159336Sdfr NFSERR_ACCES, 3169336Sdfr NFSERR_EXIST, 3179336Sdfr NFSERR_NOTDIR, 3189336Sdfr NFSERR_NOSPC, 3199336Sdfr NFSERR_ROFS, 3209336Sdfr NFSERR_NAMETOL, 3219336Sdfr NFSERR_DQUOT, 3229336Sdfr NFSERR_STALE, 3239336Sdfr NFSERR_BADHANDLE, 3249336Sdfr NFSERR_NOTSUPP, 3259336Sdfr NFSERR_SERVERFAULT, 3269336Sdfr 0, 3279336Sdfr}; 3289336Sdfr 3299336Sdfrstatic short nfsv3err_mkdir[] = { 3309336Sdfr NFSERR_IO, 3319336Sdfr NFSERR_IO, 3329336Sdfr NFSERR_ACCES, 3339336Sdfr NFSERR_EXIST, 3349336Sdfr NFSERR_NOTDIR, 3359336Sdfr NFSERR_NOSPC, 3369336Sdfr NFSERR_ROFS, 3379336Sdfr NFSERR_NAMETOL, 3389336Sdfr NFSERR_DQUOT, 3399336Sdfr NFSERR_STALE, 3409336Sdfr NFSERR_BADHANDLE, 3419336Sdfr NFSERR_NOTSUPP, 3429336Sdfr NFSERR_SERVERFAULT, 3439336Sdfr 0, 3449336Sdfr}; 3459336Sdfr 3469336Sdfrstatic short nfsv3err_symlink[] = { 3479336Sdfr NFSERR_IO, 3489336Sdfr NFSERR_IO, 3499336Sdfr NFSERR_ACCES, 3509336Sdfr NFSERR_EXIST, 3519336Sdfr NFSERR_NOTDIR, 3529336Sdfr NFSERR_NOSPC, 3539336Sdfr NFSERR_ROFS, 3549336Sdfr NFSERR_NAMETOL, 3559336Sdfr NFSERR_DQUOT, 3569336Sdfr NFSERR_STALE, 3579336Sdfr NFSERR_BADHANDLE, 3589336Sdfr NFSERR_NOTSUPP, 3599336Sdfr NFSERR_SERVERFAULT, 3609336Sdfr 0, 3619336Sdfr}; 3629336Sdfr 3639336Sdfrstatic short nfsv3err_mknod[] = { 3649336Sdfr NFSERR_IO, 3659336Sdfr NFSERR_IO, 3669336Sdfr NFSERR_ACCES, 3679336Sdfr NFSERR_EXIST, 3689336Sdfr NFSERR_NOTDIR, 3699336Sdfr NFSERR_NOSPC, 3709336Sdfr NFSERR_ROFS, 3719336Sdfr NFSERR_NAMETOL, 3729336Sdfr NFSERR_DQUOT, 3739336Sdfr NFSERR_STALE, 3749336Sdfr NFSERR_BADHANDLE, 3759336Sdfr NFSERR_NOTSUPP, 3769336Sdfr NFSERR_SERVERFAULT, 3779336Sdfr NFSERR_BADTYPE, 3789336Sdfr 0, 3799336Sdfr}; 3809336Sdfr 3819336Sdfrstatic short nfsv3err_remove[] = { 3829336Sdfr NFSERR_IO, 3839336Sdfr NFSERR_NOENT, 3849336Sdfr NFSERR_IO, 3859336Sdfr NFSERR_ACCES, 3869336Sdfr NFSERR_NOTDIR, 3879336Sdfr NFSERR_ROFS, 3889336Sdfr NFSERR_NAMETOL, 3899336Sdfr NFSERR_STALE, 3909336Sdfr NFSERR_BADHANDLE, 3919336Sdfr NFSERR_SERVERFAULT, 3929336Sdfr 0, 3939336Sdfr}; 3949336Sdfr 3959336Sdfrstatic short nfsv3err_rmdir[] = { 3969336Sdfr NFSERR_IO, 3979336Sdfr NFSERR_NOENT, 3989336Sdfr NFSERR_IO, 3999336Sdfr NFSERR_ACCES, 4009336Sdfr NFSERR_EXIST, 4019336Sdfr NFSERR_NOTDIR, 4029336Sdfr NFSERR_INVAL, 4039336Sdfr NFSERR_ROFS, 4049336Sdfr NFSERR_NAMETOL, 4059336Sdfr NFSERR_NOTEMPTY, 4069336Sdfr NFSERR_STALE, 4079336Sdfr NFSERR_BADHANDLE, 4089336Sdfr NFSERR_NOTSUPP, 4099336Sdfr NFSERR_SERVERFAULT, 4109336Sdfr 0, 4119336Sdfr}; 4129336Sdfr 4139336Sdfrstatic short nfsv3err_rename[] = { 4149336Sdfr NFSERR_IO, 4159336Sdfr NFSERR_NOENT, 4169336Sdfr NFSERR_IO, 4179336Sdfr NFSERR_ACCES, 4189336Sdfr NFSERR_EXIST, 4199336Sdfr NFSERR_XDEV, 4209336Sdfr NFSERR_NOTDIR, 4219336Sdfr NFSERR_ISDIR, 4229336Sdfr NFSERR_INVAL, 4239336Sdfr NFSERR_NOSPC, 4249336Sdfr NFSERR_ROFS, 4259336Sdfr NFSERR_MLINK, 4269336Sdfr NFSERR_NAMETOL, 4279336Sdfr NFSERR_NOTEMPTY, 4289336Sdfr NFSERR_DQUOT, 4299336Sdfr NFSERR_STALE, 4309336Sdfr NFSERR_BADHANDLE, 4319336Sdfr NFSERR_NOTSUPP, 4329336Sdfr NFSERR_SERVERFAULT, 4339336Sdfr 0, 4349336Sdfr}; 4359336Sdfr 4369336Sdfrstatic short nfsv3err_link[] = { 4379336Sdfr NFSERR_IO, 4389336Sdfr NFSERR_IO, 4399336Sdfr NFSERR_ACCES, 4409336Sdfr NFSERR_EXIST, 4419336Sdfr NFSERR_XDEV, 4429336Sdfr NFSERR_NOTDIR, 4439336Sdfr NFSERR_INVAL, 4449336Sdfr NFSERR_NOSPC, 4459336Sdfr NFSERR_ROFS, 4469336Sdfr NFSERR_MLINK, 4479336Sdfr NFSERR_NAMETOL, 4489336Sdfr NFSERR_DQUOT, 4499336Sdfr NFSERR_STALE, 4509336Sdfr NFSERR_BADHANDLE, 4519336Sdfr NFSERR_NOTSUPP, 4529336Sdfr NFSERR_SERVERFAULT, 4539336Sdfr 0, 4549336Sdfr}; 4559336Sdfr 4569336Sdfrstatic short nfsv3err_readdir[] = { 4579336Sdfr NFSERR_IO, 4589336Sdfr NFSERR_IO, 4599336Sdfr NFSERR_ACCES, 4609336Sdfr NFSERR_NOTDIR, 4619336Sdfr NFSERR_STALE, 4629336Sdfr NFSERR_BADHANDLE, 4639336Sdfr NFSERR_BAD_COOKIE, 4649336Sdfr NFSERR_TOOSMALL, 4659336Sdfr NFSERR_SERVERFAULT, 4669336Sdfr 0, 4679336Sdfr}; 4689336Sdfr 4699336Sdfrstatic short nfsv3err_readdirplus[] = { 4709336Sdfr NFSERR_IO, 4719336Sdfr NFSERR_IO, 4729336Sdfr NFSERR_ACCES, 4739336Sdfr NFSERR_NOTDIR, 4749336Sdfr NFSERR_STALE, 4759336Sdfr NFSERR_BADHANDLE, 4769336Sdfr NFSERR_BAD_COOKIE, 4779336Sdfr NFSERR_NOTSUPP, 4789336Sdfr NFSERR_TOOSMALL, 4799336Sdfr NFSERR_SERVERFAULT, 4809336Sdfr 0, 4819336Sdfr}; 4829336Sdfr 4839336Sdfrstatic short nfsv3err_fsstat[] = { 4849336Sdfr NFSERR_IO, 4859336Sdfr NFSERR_IO, 4869336Sdfr NFSERR_STALE, 4879336Sdfr NFSERR_BADHANDLE, 4889336Sdfr NFSERR_SERVERFAULT, 4899336Sdfr 0, 4909336Sdfr}; 4919336Sdfr 4929336Sdfrstatic short nfsv3err_fsinfo[] = { 4939336Sdfr NFSERR_STALE, 4949336Sdfr NFSERR_STALE, 4959336Sdfr NFSERR_BADHANDLE, 4969336Sdfr NFSERR_SERVERFAULT, 4979336Sdfr 0, 4989336Sdfr}; 4999336Sdfr 5009336Sdfrstatic short nfsv3err_pathconf[] = { 5019336Sdfr NFSERR_STALE, 5029336Sdfr NFSERR_STALE, 5039336Sdfr NFSERR_BADHANDLE, 5049336Sdfr NFSERR_SERVERFAULT, 5059336Sdfr 0, 5069336Sdfr}; 5079336Sdfr 5089336Sdfrstatic short nfsv3err_commit[] = { 5099336Sdfr NFSERR_IO, 5109336Sdfr NFSERR_IO, 5119336Sdfr NFSERR_STALE, 5129336Sdfr NFSERR_BADHANDLE, 5139336Sdfr NFSERR_SERVERFAULT, 5149336Sdfr 0, 5159336Sdfr}; 5169336Sdfr 5179336Sdfrstatic short *nfsrv_v3errmap[] = { 5189336Sdfr nfsv3err_null, 5199336Sdfr nfsv3err_getattr, 5209336Sdfr nfsv3err_setattr, 5219336Sdfr nfsv3err_lookup, 5229336Sdfr nfsv3err_access, 5239336Sdfr nfsv3err_readlink, 5249336Sdfr nfsv3err_read, 5259336Sdfr nfsv3err_write, 5269336Sdfr nfsv3err_create, 5279336Sdfr nfsv3err_mkdir, 5289336Sdfr nfsv3err_symlink, 5299336Sdfr nfsv3err_mknod, 5309336Sdfr nfsv3err_remove, 5319336Sdfr nfsv3err_rmdir, 5329336Sdfr nfsv3err_rename, 5339336Sdfr nfsv3err_link, 5349336Sdfr nfsv3err_readdir, 5359336Sdfr nfsv3err_readdirplus, 5369336Sdfr nfsv3err_fsstat, 5379336Sdfr nfsv3err_fsinfo, 5389336Sdfr nfsv3err_pathconf, 5399336Sdfr nfsv3err_commit, 5409336Sdfr}; 5419336Sdfr 54213416Sphk#endif /* NFS_NOSERVER */ 54313416Sphk 5441541Srgrimesextern struct nfsrtt nfsrtt; 5451541Srgrimesextern time_t nqnfsstarttime; 5461541Srgrimesextern int nqsrv_clockskew; 5471541Srgrimesextern int nqsrv_writeslack; 5481541Srgrimesextern int nqsrv_maxlease; 5499336Sdfrextern struct nfsstats nfsstats; 5509336Sdfrextern int nqnfs_piggy[NFS_NPROCS]; 5519336Sdfrextern nfstype nfsv2_type[9]; 5529336Sdfrextern nfstype nfsv3_type[9]; 5539336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl; 5549336Sdfrextern u_long nfsnodehash; 5551541Srgrimes 5562997Swollmanstruct nfssvc_args; 5572997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 5582997Swollman 5593664SphkLIST_HEAD(nfsnodehashhead, nfsnode); 5603664Sphk 56127446Sdfrint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 56227446Sdfr 56334961Sphku_quad_t 56434961Sphknfs_curusec() 56534961Sphk{ 56634961Sphk struct timeval tv; 56734961Sphk 56834961Sphk getmicrotime(&tv); 56934961Sphk return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); 57034961Sphk} 57134961Sphk 5721541Srgrimes/* 5731541Srgrimes * Create the header for an rpc request packet 5741541Srgrimes * The hsiz is the size of the rest of the nfs request header. 5751541Srgrimes * (just used to decide if a cluster is a good idea) 5761541Srgrimes */ 5771541Srgrimesstruct mbuf * 5781541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp) 5791541Srgrimes struct vnode *vp; 5801541Srgrimes u_long procid; 5811541Srgrimes int hsiz; 5821541Srgrimes caddr_t *bposp; 5831541Srgrimes{ 5841541Srgrimes register struct mbuf *mb; 58536541Speter register u_int32_t *tl; 5861541Srgrimes register caddr_t bpos; 5871541Srgrimes struct mbuf *mb2; 5881541Srgrimes struct nfsmount *nmp; 5891541Srgrimes int nqflag; 5901541Srgrimes 5911541Srgrimes MGET(mb, M_WAIT, MT_DATA); 5921541Srgrimes if (hsiz >= MINCLSIZE) 5931541Srgrimes MCLGET(mb, M_WAIT); 5941541Srgrimes mb->m_len = 0; 5951541Srgrimes bpos = mtod(mb, caddr_t); 5968876Srgrimes 5971541Srgrimes /* 5981541Srgrimes * For NQNFS, add lease request. 5991541Srgrimes */ 6001541Srgrimes if (vp) { 6011541Srgrimes nmp = VFSTONFS(vp->v_mount); 6021541Srgrimes if (nmp->nm_flag & NFSMNT_NQNFS) { 6031541Srgrimes nqflag = NQNFS_NEEDLEASE(vp, procid); 6041541Srgrimes if (nqflag) { 60536541Speter nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 6061541Srgrimes *tl++ = txdr_unsigned(nqflag); 6071541Srgrimes *tl = txdr_unsigned(nmp->nm_leaseterm); 6081541Srgrimes } else { 60936541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 6101541Srgrimes *tl = 0; 6111541Srgrimes } 6121541Srgrimes } 6131541Srgrimes } 6141541Srgrimes /* Finally, return values */ 6151541Srgrimes *bposp = bpos; 6161541Srgrimes return (mb); 6171541Srgrimes} 6181541Srgrimes 6191541Srgrimes/* 6201541Srgrimes * Build the RPC header and fill in the authorization info. 6211541Srgrimes * The authorization string argument is only used when the credentials 6221541Srgrimes * come from outside of the kernel. 6231541Srgrimes * Returns the head of the mbuf list. 6241541Srgrimes */ 6251541Srgrimesstruct mbuf * 6269336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 6279336Sdfr verf_str, mrest, mrest_len, mbp, xidp) 6281541Srgrimes register struct ucred *cr; 6299336Sdfr int nmflag; 6301541Srgrimes int procid; 6311541Srgrimes int auth_type; 6321541Srgrimes int auth_len; 6331541Srgrimes char *auth_str; 6349336Sdfr int verf_len; 6359336Sdfr char *verf_str; 6361541Srgrimes struct mbuf *mrest; 6371541Srgrimes int mrest_len; 6381541Srgrimes struct mbuf **mbp; 63936541Speter u_int32_t *xidp; 6401541Srgrimes{ 6411541Srgrimes register struct mbuf *mb; 64236541Speter register u_int32_t *tl; 6431541Srgrimes register caddr_t bpos; 6441541Srgrimes register int i; 6451541Srgrimes struct mbuf *mreq, *mb2; 6461541Srgrimes int siz, grpsiz, authsiz; 6471541Srgrimes 6481541Srgrimes authsiz = nfsm_rndup(auth_len); 6491541Srgrimes MGETHDR(mb, M_WAIT, MT_DATA); 6509336Sdfr if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 6511541Srgrimes MCLGET(mb, M_WAIT); 6529336Sdfr } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 6539336Sdfr MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 6541541Srgrimes } else { 6559336Sdfr MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 6561541Srgrimes } 6571541Srgrimes mb->m_len = 0; 6581541Srgrimes mreq = mb; 6591541Srgrimes bpos = mtod(mb, caddr_t); 6601541Srgrimes 6611541Srgrimes /* 6621541Srgrimes * First the RPC header. 6631541Srgrimes */ 66436541Speter nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 66517186Sdfr 66635066Sphk /* Get a pretty random xid to start with */ 66735066Sphk if (!nfs_xid) 66835066Sphk nfs_xid = random(); 66917186Sdfr /* 67017186Sdfr * Skip zero xid if it should ever happen. 67117186Sdfr */ 6721541Srgrimes if (++nfs_xid == 0) 6731541Srgrimes nfs_xid++; 67417186Sdfr 6751541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 6761541Srgrimes *tl++ = rpc_call; 6771541Srgrimes *tl++ = rpc_vers; 6789336Sdfr if (nmflag & NFSMNT_NQNFS) { 6791541Srgrimes *tl++ = txdr_unsigned(NQNFS_PROG); 6809336Sdfr *tl++ = txdr_unsigned(NQNFS_VER3); 6811541Srgrimes } else { 6821541Srgrimes *tl++ = txdr_unsigned(NFS_PROG); 6839336Sdfr if (nmflag & NFSMNT_NFSV3) 6849336Sdfr *tl++ = txdr_unsigned(NFS_VER3); 6859336Sdfr else 6869336Sdfr *tl++ = txdr_unsigned(NFS_VER2); 6871541Srgrimes } 6889336Sdfr if (nmflag & NFSMNT_NFSV3) 6899336Sdfr *tl++ = txdr_unsigned(procid); 6909336Sdfr else 6919336Sdfr *tl++ = txdr_unsigned(nfsv2_procid[procid]); 6921541Srgrimes 6931541Srgrimes /* 6941541Srgrimes * And then the authorization cred. 6951541Srgrimes */ 6961541Srgrimes *tl++ = txdr_unsigned(auth_type); 6971541Srgrimes *tl = txdr_unsigned(authsiz); 6981541Srgrimes switch (auth_type) { 6991541Srgrimes case RPCAUTH_UNIX: 70036541Speter nfsm_build(tl, u_int32_t *, auth_len); 7011541Srgrimes *tl++ = 0; /* stamp ?? */ 7021541Srgrimes *tl++ = 0; /* NULL hostname */ 7031541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 7041541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 7051541Srgrimes grpsiz = (auth_len >> 2) - 5; 7061541Srgrimes *tl++ = txdr_unsigned(grpsiz); 7071541Srgrimes for (i = 1; i <= grpsiz; i++) 7081541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 7091541Srgrimes break; 7109336Sdfr case RPCAUTH_KERB4: 7111541Srgrimes siz = auth_len; 7121541Srgrimes while (siz > 0) { 7131541Srgrimes if (M_TRAILINGSPACE(mb) == 0) { 7141541Srgrimes MGET(mb2, M_WAIT, MT_DATA); 7151541Srgrimes if (siz >= MINCLSIZE) 7161541Srgrimes MCLGET(mb2, M_WAIT); 7171541Srgrimes mb->m_next = mb2; 7181541Srgrimes mb = mb2; 7191541Srgrimes mb->m_len = 0; 7201541Srgrimes bpos = mtod(mb, caddr_t); 7211541Srgrimes } 7221541Srgrimes i = min(siz, M_TRAILINGSPACE(mb)); 7231541Srgrimes bcopy(auth_str, bpos, i); 7241541Srgrimes mb->m_len += i; 7251541Srgrimes auth_str += i; 7261541Srgrimes bpos += i; 7271541Srgrimes siz -= i; 7281541Srgrimes } 7291541Srgrimes if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 7301541Srgrimes for (i = 0; i < siz; i++) 7311541Srgrimes *bpos++ = '\0'; 7321541Srgrimes mb->m_len += siz; 7331541Srgrimes } 7341541Srgrimes break; 7351541Srgrimes }; 7369336Sdfr 7379336Sdfr /* 7389336Sdfr * And the verifier... 7399336Sdfr */ 74036541Speter nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7419336Sdfr if (verf_str) { 7429336Sdfr *tl++ = txdr_unsigned(RPCAUTH_KERB4); 7439336Sdfr *tl = txdr_unsigned(verf_len); 7449336Sdfr siz = verf_len; 7459336Sdfr while (siz > 0) { 7469336Sdfr if (M_TRAILINGSPACE(mb) == 0) { 7479336Sdfr MGET(mb2, M_WAIT, MT_DATA); 7489336Sdfr if (siz >= MINCLSIZE) 7499336Sdfr MCLGET(mb2, M_WAIT); 7509336Sdfr mb->m_next = mb2; 7519336Sdfr mb = mb2; 7529336Sdfr mb->m_len = 0; 7539336Sdfr bpos = mtod(mb, caddr_t); 7549336Sdfr } 7559336Sdfr i = min(siz, M_TRAILINGSPACE(mb)); 7569336Sdfr bcopy(verf_str, bpos, i); 7579336Sdfr mb->m_len += i; 7589336Sdfr verf_str += i; 7599336Sdfr bpos += i; 7609336Sdfr siz -= i; 7619336Sdfr } 7629336Sdfr if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 7639336Sdfr for (i = 0; i < siz; i++) 7649336Sdfr *bpos++ = '\0'; 7659336Sdfr mb->m_len += siz; 7669336Sdfr } 7679336Sdfr } else { 7689336Sdfr *tl++ = txdr_unsigned(RPCAUTH_NULL); 7699336Sdfr *tl = 0; 7709336Sdfr } 7711541Srgrimes mb->m_next = mrest; 7729336Sdfr mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 7731541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 7741541Srgrimes *mbp = mb; 7751541Srgrimes return (mreq); 7761541Srgrimes} 7771541Srgrimes 7781541Srgrimes/* 7791541Srgrimes * copies mbuf chain to the uio scatter/gather list 7801541Srgrimes */ 7811549Srgrimesint 7821541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos) 7831541Srgrimes struct mbuf **mrep; 7841541Srgrimes register struct uio *uiop; 7851541Srgrimes int siz; 7861541Srgrimes caddr_t *dpos; 7871541Srgrimes{ 7881541Srgrimes register char *mbufcp, *uiocp; 7891541Srgrimes register int xfer, left, len; 7901541Srgrimes register struct mbuf *mp; 7911541Srgrimes long uiosiz, rem; 7921541Srgrimes int error = 0; 7931541Srgrimes 7941541Srgrimes mp = *mrep; 7951541Srgrimes mbufcp = *dpos; 7961541Srgrimes len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 7971541Srgrimes rem = nfsm_rndup(siz)-siz; 7981541Srgrimes while (siz > 0) { 7991541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 8001541Srgrimes return (EFBIG); 8011541Srgrimes left = uiop->uio_iov->iov_len; 8021541Srgrimes uiocp = uiop->uio_iov->iov_base; 8031541Srgrimes if (left > siz) 8041541Srgrimes left = siz; 8051541Srgrimes uiosiz = left; 8061541Srgrimes while (left > 0) { 8071541Srgrimes while (len == 0) { 8081541Srgrimes mp = mp->m_next; 8091541Srgrimes if (mp == NULL) 8101541Srgrimes return (EBADRPC); 8111541Srgrimes mbufcp = mtod(mp, caddr_t); 8121541Srgrimes len = mp->m_len; 8131541Srgrimes } 8141541Srgrimes xfer = (left > len) ? len : left; 8151541Srgrimes#ifdef notdef 8161541Srgrimes /* Not Yet.. */ 8171541Srgrimes if (uiop->uio_iov->iov_op != NULL) 8181541Srgrimes (*(uiop->uio_iov->iov_op)) 8191541Srgrimes (mbufcp, uiocp, xfer); 8201541Srgrimes else 8211541Srgrimes#endif 8221541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 8231541Srgrimes bcopy(mbufcp, uiocp, xfer); 8241541Srgrimes else 8251541Srgrimes copyout(mbufcp, uiocp, xfer); 8261541Srgrimes left -= xfer; 8271541Srgrimes len -= xfer; 8281541Srgrimes mbufcp += xfer; 8291541Srgrimes uiocp += xfer; 8301541Srgrimes uiop->uio_offset += xfer; 8311541Srgrimes uiop->uio_resid -= xfer; 8321541Srgrimes } 8331541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 8341541Srgrimes uiop->uio_iovcnt--; 8351541Srgrimes uiop->uio_iov++; 8361541Srgrimes } else { 8371541Srgrimes uiop->uio_iov->iov_base += uiosiz; 8381541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 8391541Srgrimes } 8401541Srgrimes siz -= uiosiz; 8411541Srgrimes } 8421541Srgrimes *dpos = mbufcp; 8431541Srgrimes *mrep = mp; 8441541Srgrimes if (rem > 0) { 8451541Srgrimes if (len < rem) 8461541Srgrimes error = nfs_adv(mrep, dpos, rem, len); 8471541Srgrimes else 8481541Srgrimes *dpos += rem; 8491541Srgrimes } 8501541Srgrimes return (error); 8511541Srgrimes} 8521541Srgrimes 8531541Srgrimes/* 85417186Sdfr * copies a uio scatter/gather list to an mbuf chain. 85517186Sdfr * NOTE: can ony handle iovcnt == 1 8561541Srgrimes */ 8571549Srgrimesint 8581541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos) 8591541Srgrimes register struct uio *uiop; 8601541Srgrimes struct mbuf **mq; 8611541Srgrimes int siz; 8621541Srgrimes caddr_t *bpos; 8631541Srgrimes{ 8641541Srgrimes register char *uiocp; 8651541Srgrimes register struct mbuf *mp, *mp2; 8661541Srgrimes register int xfer, left, mlen; 8671541Srgrimes int uiosiz, clflg, rem; 8681541Srgrimes char *cp; 8691541Srgrimes 87036519Speter#ifdef DIAGNOSTIC 87117186Sdfr if (uiop->uio_iovcnt != 1) 87217186Sdfr panic("nfsm_uiotombuf: iovcnt != 1"); 87336519Speter#endif 87417186Sdfr 8751541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 8761541Srgrimes clflg = 1; 8771541Srgrimes else 8781541Srgrimes clflg = 0; 8791541Srgrimes rem = nfsm_rndup(siz)-siz; 8801541Srgrimes mp = mp2 = *mq; 8811541Srgrimes while (siz > 0) { 8821541Srgrimes left = uiop->uio_iov->iov_len; 8831541Srgrimes uiocp = uiop->uio_iov->iov_base; 8841541Srgrimes if (left > siz) 8851541Srgrimes left = siz; 8861541Srgrimes uiosiz = left; 8871541Srgrimes while (left > 0) { 8881541Srgrimes mlen = M_TRAILINGSPACE(mp); 8891541Srgrimes if (mlen == 0) { 8901541Srgrimes MGET(mp, M_WAIT, MT_DATA); 8911541Srgrimes if (clflg) 8921541Srgrimes MCLGET(mp, M_WAIT); 8931541Srgrimes mp->m_len = 0; 8941541Srgrimes mp2->m_next = mp; 8951541Srgrimes mp2 = mp; 8961541Srgrimes mlen = M_TRAILINGSPACE(mp); 8971541Srgrimes } 8981541Srgrimes xfer = (left > mlen) ? mlen : left; 8991541Srgrimes#ifdef notdef 9001541Srgrimes /* Not Yet.. */ 9011541Srgrimes if (uiop->uio_iov->iov_op != NULL) 9021541Srgrimes (*(uiop->uio_iov->iov_op)) 9031541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9041541Srgrimes else 9051541Srgrimes#endif 9061541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 9071541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9081541Srgrimes else 9091541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 9101541Srgrimes mp->m_len += xfer; 9111541Srgrimes left -= xfer; 9121541Srgrimes uiocp += xfer; 9131541Srgrimes uiop->uio_offset += xfer; 9141541Srgrimes uiop->uio_resid -= xfer; 9151541Srgrimes } 91617186Sdfr uiop->uio_iov->iov_base += uiosiz; 91717186Sdfr uiop->uio_iov->iov_len -= uiosiz; 9181541Srgrimes siz -= uiosiz; 9191541Srgrimes } 9201541Srgrimes if (rem > 0) { 9211541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 9221541Srgrimes MGET(mp, M_WAIT, MT_DATA); 9231541Srgrimes mp->m_len = 0; 9241541Srgrimes mp2->m_next = mp; 9251541Srgrimes } 9261541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 9271541Srgrimes for (left = 0; left < rem; left++) 9281541Srgrimes *cp++ = '\0'; 9291541Srgrimes mp->m_len += rem; 9301541Srgrimes *bpos = cp; 9311541Srgrimes } else 9321541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 9331541Srgrimes *mq = mp; 9341541Srgrimes return (0); 9351541Srgrimes} 9361541Srgrimes 9371541Srgrimes/* 9381541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous 9391541Srgrimes * pointed to by returned val. 9401541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 9411541Srgrimes * cases. (The macros use the vars. dpos and dpos2) 9421541Srgrimes */ 9431549Srgrimesint 9441541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2) 9451541Srgrimes struct mbuf **mdp; 9461541Srgrimes caddr_t *dposp; 9471541Srgrimes int siz; 9481541Srgrimes int left; 9491541Srgrimes caddr_t *cp2; 9501541Srgrimes{ 9511541Srgrimes register struct mbuf *mp, *mp2; 9521541Srgrimes register int siz2, xfer; 9531541Srgrimes register caddr_t p; 9541541Srgrimes 9551541Srgrimes mp = *mdp; 9561541Srgrimes while (left == 0) { 9571541Srgrimes *mdp = mp = mp->m_next; 9581541Srgrimes if (mp == NULL) 9591541Srgrimes return (EBADRPC); 9601541Srgrimes left = mp->m_len; 9611541Srgrimes *dposp = mtod(mp, caddr_t); 9621541Srgrimes } 9631541Srgrimes if (left >= siz) { 9641541Srgrimes *cp2 = *dposp; 9651541Srgrimes *dposp += siz; 9661541Srgrimes } else if (mp->m_next == NULL) { 9671541Srgrimes return (EBADRPC); 9681541Srgrimes } else if (siz > MHLEN) { 9691541Srgrimes panic("nfs S too big"); 9701541Srgrimes } else { 9711541Srgrimes MGET(mp2, M_WAIT, MT_DATA); 9721541Srgrimes mp2->m_next = mp->m_next; 9731541Srgrimes mp->m_next = mp2; 9741541Srgrimes mp->m_len -= left; 9751541Srgrimes mp = mp2; 9761541Srgrimes *cp2 = p = mtod(mp, caddr_t); 9771541Srgrimes bcopy(*dposp, p, left); /* Copy what was left */ 9781541Srgrimes siz2 = siz-left; 9791541Srgrimes p += left; 9801541Srgrimes mp2 = mp->m_next; 9811541Srgrimes /* Loop around copying up the siz2 bytes */ 9821541Srgrimes while (siz2 > 0) { 9831541Srgrimes if (mp2 == NULL) 9841541Srgrimes return (EBADRPC); 9851541Srgrimes xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 9861541Srgrimes if (xfer > 0) { 9871541Srgrimes bcopy(mtod(mp2, caddr_t), p, xfer); 9881541Srgrimes NFSMADV(mp2, xfer); 9891541Srgrimes mp2->m_len -= xfer; 9901541Srgrimes p += xfer; 9911541Srgrimes siz2 -= xfer; 9921541Srgrimes } 9931541Srgrimes if (siz2 > 0) 9941541Srgrimes mp2 = mp2->m_next; 9951541Srgrimes } 9961541Srgrimes mp->m_len = siz; 9971541Srgrimes *mdp = mp2; 9981541Srgrimes *dposp = mtod(mp2, caddr_t); 9991541Srgrimes } 10001541Srgrimes return (0); 10011541Srgrimes} 10021541Srgrimes 10031541Srgrimes/* 10041541Srgrimes * Advance the position in the mbuf chain. 10051541Srgrimes */ 10061549Srgrimesint 10071541Srgrimesnfs_adv(mdp, dposp, offs, left) 10081541Srgrimes struct mbuf **mdp; 10091541Srgrimes caddr_t *dposp; 10101541Srgrimes int offs; 10111541Srgrimes int left; 10121541Srgrimes{ 10131541Srgrimes register struct mbuf *m; 10141541Srgrimes register int s; 10151541Srgrimes 10161541Srgrimes m = *mdp; 10171541Srgrimes s = left; 10181541Srgrimes while (s < offs) { 10191541Srgrimes offs -= s; 10201541Srgrimes m = m->m_next; 10211541Srgrimes if (m == NULL) 10221541Srgrimes return (EBADRPC); 10231541Srgrimes s = m->m_len; 10241541Srgrimes } 10251541Srgrimes *mdp = m; 10261541Srgrimes *dposp = mtod(m, caddr_t)+offs; 10271541Srgrimes return (0); 10281541Srgrimes} 10291541Srgrimes 10301541Srgrimes/* 10311541Srgrimes * Copy a string into mbufs for the hard cases... 10321541Srgrimes */ 10331549Srgrimesint 10341541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz) 10351541Srgrimes struct mbuf **mb; 10361541Srgrimes char **bpos; 103736511Speter const char *cp; 10381541Srgrimes long siz; 10391541Srgrimes{ 104036519Speter register struct mbuf *m1 = NULL, *m2; 10411541Srgrimes long left, xfer, len, tlen; 104236541Speter u_int32_t *tl; 10431541Srgrimes int putsize; 10441541Srgrimes 10451541Srgrimes putsize = 1; 10461541Srgrimes m2 = *mb; 10471541Srgrimes left = M_TRAILINGSPACE(m2); 10481541Srgrimes if (left > 0) { 104936541Speter tl = ((u_int32_t *)(*bpos)); 10501541Srgrimes *tl++ = txdr_unsigned(siz); 10511541Srgrimes putsize = 0; 10521541Srgrimes left -= NFSX_UNSIGNED; 10531541Srgrimes m2->m_len += NFSX_UNSIGNED; 10541541Srgrimes if (left > 0) { 10551541Srgrimes bcopy(cp, (caddr_t) tl, left); 10561541Srgrimes siz -= left; 10571541Srgrimes cp += left; 10581541Srgrimes m2->m_len += left; 10591541Srgrimes left = 0; 10601541Srgrimes } 10611541Srgrimes } 10621541Srgrimes /* Loop around adding mbufs */ 10631541Srgrimes while (siz > 0) { 10641541Srgrimes MGET(m1, M_WAIT, MT_DATA); 10651541Srgrimes if (siz > MLEN) 10661541Srgrimes MCLGET(m1, M_WAIT); 10671541Srgrimes m1->m_len = NFSMSIZ(m1); 10681541Srgrimes m2->m_next = m1; 10691541Srgrimes m2 = m1; 107036541Speter tl = mtod(m1, u_int32_t *); 10711541Srgrimes tlen = 0; 10721541Srgrimes if (putsize) { 10731541Srgrimes *tl++ = txdr_unsigned(siz); 10741541Srgrimes m1->m_len -= NFSX_UNSIGNED; 10751541Srgrimes tlen = NFSX_UNSIGNED; 10761541Srgrimes putsize = 0; 10771541Srgrimes } 10781541Srgrimes if (siz < m1->m_len) { 10791541Srgrimes len = nfsm_rndup(siz); 10801541Srgrimes xfer = siz; 10811541Srgrimes if (xfer < len) 10821541Srgrimes *(tl+(xfer>>2)) = 0; 10831541Srgrimes } else { 10841541Srgrimes xfer = len = m1->m_len; 10851541Srgrimes } 10861541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 10871541Srgrimes m1->m_len = len+tlen; 10881541Srgrimes siz -= xfer; 10891541Srgrimes cp += xfer; 10901541Srgrimes } 10911541Srgrimes *mb = m1; 10921541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 10931541Srgrimes return (0); 10941541Srgrimes} 10951541Srgrimes 10961541Srgrimes/* 10971541Srgrimes * Called once to initialize data structures... 10981541Srgrimes */ 10991549Srgrimesint 110022521Sdysonnfs_init(vfsp) 110122521Sdyson struct vfsconf *vfsp; 11021541Srgrimes{ 11031541Srgrimes register int i; 11041541Srgrimes 110536329Speter nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 110636329Speter 110722521Sdyson nfs_mount_type = vfsp->vfc_typenum; 11081541Srgrimes nfsrtt.pos = 0; 11091541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 11101541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 11111541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 11121541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 11131541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 11141541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 11151541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 11161541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 11179336Sdfr rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 11181541Srgrimes nfs_prog = txdr_unsigned(NFS_PROG); 11199336Sdfr nqnfs_prog = txdr_unsigned(NQNFS_PROG); 11201541Srgrimes nfs_true = txdr_unsigned(TRUE); 11211541Srgrimes nfs_false = txdr_unsigned(FALSE); 11223664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 11239336Sdfr nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 11249336Sdfr if (nfs_ticks < 1) 11259336Sdfr nfs_ticks = 1; 11261541Srgrimes /* Ensure async daemons disabled */ 112719449Sdfr for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 11281541Srgrimes nfs_iodwant[i] = (struct proc *)0; 112919449Sdfr nfs_iodmount[i] = (struct nfsmount *)0; 113019449Sdfr } 11311541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 113213416Sphk#ifndef NFS_NOSERVER 11331541Srgrimes nfsrv_init(0); /* Init server data structures */ 11341541Srgrimes nfsrv_initcache(); /* Init the server request cache */ 113513416Sphk#endif 11361541Srgrimes 11371541Srgrimes /* 11381541Srgrimes * Initialize the nqnfs server stuff. 11391541Srgrimes */ 11401541Srgrimes if (nqnfsstarttime == 0) { 11411541Srgrimes nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 11421541Srgrimes + nqsrv_clockskew + nqsrv_writeslack; 11431541Srgrimes NQLOADNOVRAM(nqnfsstarttime); 11443664Sphk CIRCLEQ_INIT(&nqtimerhead); 11453664Sphk nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 11461541Srgrimes } 11471541Srgrimes 11481541Srgrimes /* 11491541Srgrimes * Initialize reply list and start timer 11501541Srgrimes */ 11513664Sphk TAILQ_INIT(&nfs_reqq); 115216365Sphk 11533305Sphk nfs_timer(0); 11541549Srgrimes 11552997Swollman /* 11562997Swollman * Set up lease_check and lease_updatetime so that other parts 11572997Swollman * of the system can call us, if we are loadable. 11582997Swollman */ 115913416Sphk#ifndef NFS_NOSERVER 116038894Sbde nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; 116130738Sphk default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; 116213416Sphk#endif 116338894Sbde nfs_prev_lease_updatetime = lease_updatetime; 11642997Swollman lease_updatetime = nfs_lease_updatetime; 116538894Sbde nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 11662997Swollman sysent[SYS_nfssvc].sy_narg = 2; 116738894Sbde nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 116830738Sphk sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 11692997Swollman 117042957Sdillon nfs_pbuf_freecnt = nswbuf / 2 + 1; 117142957Sdillon 11721549Srgrimes return (0); 11731541Srgrimes} 11741541Srgrimes 117538894Sbdeint 117638894Sbdenfs_uninit(vfsp) 117738894Sbde struct vfsconf *vfsp; 117838894Sbde{ 117938894Sbde 118038894Sbde untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 118138894Sbde nfs_mount_type = -1; 118238894Sbde#ifndef NFS_NOSERVER 118338894Sbde default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; 118438894Sbde#endif 118538894Sbde lease_updatetime = nfs_prev_lease_updatetime; 118638894Sbde sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 118738894Sbde sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 118838894Sbde return (0); 118938894Sbde} 119038894Sbde 11911541Srgrimes/* 11921541Srgrimes * Attribute cache routines. 11931541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 11941541Srgrimes * that are on the mbuf list 11951541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 11961541Srgrimes * error otherwise 11971541Srgrimes */ 11981541Srgrimes 11991541Srgrimes/* 12001541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 12011541Srgrimes * the values on the mbuf list and 12021541Srgrimes * Iff vap not NULL 12031541Srgrimes * copy the attributes to *vaper 12041541Srgrimes */ 12051549Srgrimesint 12061541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper) 12071541Srgrimes struct vnode **vpp; 12081541Srgrimes struct mbuf **mdp; 12091541Srgrimes caddr_t *dposp; 12101541Srgrimes struct vattr *vaper; 12111541Srgrimes{ 12121541Srgrimes register struct vnode *vp = *vpp; 12131541Srgrimes register struct vattr *vap; 12149336Sdfr register struct nfs_fattr *fp; 12153664Sphk register struct nfsnode *np; 121636541Speter register int32_t t1; 12179336Sdfr caddr_t cp2; 12189336Sdfr int error = 0, rdev; 12191541Srgrimes struct mbuf *md; 12201541Srgrimes enum vtype vtyp; 12211541Srgrimes u_short vmode; 12221541Srgrimes struct timespec mtime; 12239336Sdfr int v3 = NFS_ISV3(vp); 12241541Srgrimes 12251541Srgrimes md = *mdp; 12269336Sdfr t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 122743305Sdillon if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) 12281541Srgrimes return (error); 12299336Sdfr fp = (struct nfs_fattr *)cp2; 12309336Sdfr if (v3) { 12319336Sdfr vtyp = nfsv3tov_type(fp->fa_type); 12329336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 123348859Sphk rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 123416634Sbde fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 12359336Sdfr fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 12361541Srgrimes } else { 12379336Sdfr vtyp = nfsv2tov_type(fp->fa_type); 12389336Sdfr vmode = fxdr_unsigned(u_short, fp->fa_mode); 12399336Sdfr /* 12409336Sdfr * XXX 12419336Sdfr * 12429336Sdfr * The duplicate information returned in fa_type and fa_mode 12439336Sdfr * is an ambiguity in the NFS version 2 protocol. 12449336Sdfr * 12459336Sdfr * VREG should be taken literally as a regular file. If a 12469336Sdfr * server intents to return some type information differently 12479336Sdfr * in the upper bits of the mode field (e.g. for sockets, or 12489336Sdfr * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 12499336Sdfr * leave the examination of the mode bits even in the VREG 12509336Sdfr * case to avoid breakage for bogus servers, but we make sure 12519336Sdfr * that there are actually type bits set in the upper part of 12529336Sdfr * fa_mode (and failing that, trust the va_type field). 12539336Sdfr * 12549336Sdfr * NFSv3 cleared the issue, and requires fa_mode to not 12559336Sdfr * contain any type information (while also introduing sockets 12569336Sdfr * and FIFOs for fa_type). 12579336Sdfr */ 12589336Sdfr if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 12599336Sdfr vtyp = IFTOVT(vmode); 126036541Speter rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 12619336Sdfr fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 12629336Sdfr 12639336Sdfr /* 12649336Sdfr * Really ugly NFSv2 kludge. 12659336Sdfr */ 12669336Sdfr if (vtyp == VCHR && rdev == 0xffffffff) 12679336Sdfr vtyp = VFIFO; 12681541Srgrimes } 12699336Sdfr 12701541Srgrimes /* 12711541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 12728876Srgrimes * n_mtime fields. Check to see if it represents a special 12731541Srgrimes * device, and if so, check for a possible alias. Once the 12741541Srgrimes * correct vnode has been obtained, fill in the rest of the 12751541Srgrimes * information. 12761541Srgrimes */ 12771541Srgrimes np = VTONFS(vp); 127810219Sdfr if (vp->v_type != vtyp) { 12799336Sdfr vp->v_type = vtyp; 12801541Srgrimes if (vp->v_type == VFIFO) { 12811541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 12821541Srgrimes } 12831541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 12841541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 128550405Sphk addaliasu(vp, rdev); 12861541Srgrimes } 128718397Snate np->n_mtime = mtime.tv_sec; 12881541Srgrimes } 12891541Srgrimes vap = &np->n_vattr; 12901541Srgrimes vap->va_type = vtyp; 12911541Srgrimes vap->va_mode = (vmode & 07777); 129247028Sphk vap->va_rdev = rdev; 12931541Srgrimes vap->va_mtime = mtime; 12941541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 12959336Sdfr if (v3) { 12969336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 12979336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 12989336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 129947751Speter vap->va_size = fxdr_hyper(&fp->fa3_size); 13009336Sdfr vap->va_blocksize = NFS_FABLKSIZE; 130147751Speter vap->va_bytes = fxdr_hyper(&fp->fa3_used); 130236541Speter vap->va_fileid = fxdr_unsigned(int32_t, 130336541Speter fp->fa3_fileid.nfsuquad[1]); 13049336Sdfr fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 13059336Sdfr fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 13069336Sdfr vap->va_flags = 0; 13079336Sdfr vap->va_filerev = 0; 13081541Srgrimes } else { 13099336Sdfr vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 13109336Sdfr vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 13119336Sdfr vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 131236541Speter vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 131336541Speter vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 131447751Speter vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 131536541Speter * NFS_FABLKSIZE; 131636541Speter vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 13179336Sdfr fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 13181541Srgrimes vap->va_flags = 0; 131936541Speter vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 132036541Speter fp->fa2_ctime.nfsv2_sec); 132118397Snate vap->va_ctime.tv_nsec = 0; 132236541Speter vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 13231541Srgrimes vap->va_filerev = 0; 13241541Srgrimes } 13251541Srgrimes if (vap->va_size != np->n_size) { 13261541Srgrimes if (vap->va_type == VREG) { 13271541Srgrimes if (np->n_flag & NMODIFIED) { 13281541Srgrimes if (vap->va_size < np->n_size) 13291541Srgrimes vap->va_size = np->n_size; 13301541Srgrimes else 13311541Srgrimes np->n_size = vap->va_size; 133254480Sdillon } else { 13331541Srgrimes np->n_size = vap->va_size; 133454480Sdillon } 133541026Speter vnode_pager_setsize(vp, np->n_size); 133654480Sdillon } else { 13371541Srgrimes np->n_size = vap->va_size; 133854480Sdillon } 13391541Srgrimes } 134034961Sphk np->n_attrstamp = time_second; 13411541Srgrimes if (vaper != NULL) { 13421541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 13431541Srgrimes if (np->n_flag & NCHG) { 13449336Sdfr if (np->n_flag & NACC) 13459336Sdfr vaper->va_atime = np->n_atim; 13469336Sdfr if (np->n_flag & NUPD) 13479336Sdfr vaper->va_mtime = np->n_mtim; 13481541Srgrimes } 13491541Srgrimes } 13501541Srgrimes return (0); 13511541Srgrimes} 13521541Srgrimes 135336176Speter#ifdef NFS_ACDEBUG 135436176Speter#include <sys/sysctl.h> 135544101SbdeSYSCTL_DECL(_vfs_nfs); 135636176Speterstatic int nfs_acdebug; 135736176SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 135836176Speter#endif 135936176Speter 13601541Srgrimes/* 13611541Srgrimes * Check the time stamp 13621541Srgrimes * If the cache is valid, copy contents to *vap and return 0 13631541Srgrimes * otherwise return an error 13641541Srgrimes */ 13651549Srgrimesint 13661541Srgrimesnfs_getattrcache(vp, vaper) 13671541Srgrimes register struct vnode *vp; 13681541Srgrimes struct vattr *vaper; 13691541Srgrimes{ 137036176Speter register struct nfsnode *np; 13711541Srgrimes register struct vattr *vap; 137236176Speter struct nfsmount *nmp; 137336176Speter int timeo; 13741541Srgrimes 137536176Speter np = VTONFS(vp); 137636176Speter vap = &np->n_vattr; 137736176Speter nmp = VFSTONFS(vp->v_mount); 137836176Speter /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 137936176Speter timeo = (time_second - np->n_mtime) / 10; 138036176Speter 138136176Speter#ifdef NFS_ACDEBUG 138236176Speter if (nfs_acdebug>1) 138336176Speter printf("nfs_getattrcache: initial timeo = %d\n", timeo); 138436176Speter#endif 138536176Speter 138636176Speter if (vap->va_type == VDIR) { 138736176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 138836176Speter timeo = nmp->nm_acdirmin; 138936176Speter else if (timeo > nmp->nm_acdirmax) 139036176Speter timeo = nmp->nm_acdirmax; 139136176Speter } else { 139236176Speter if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 139336176Speter timeo = nmp->nm_acregmin; 139436176Speter else if (timeo > nmp->nm_acregmax) 139536176Speter timeo = nmp->nm_acregmax; 139636176Speter } 139736176Speter 139836176Speter#ifdef NFS_ACDEBUG 139936176Speter if (nfs_acdebug > 2) 140036176Speter printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 140136176Speter nmp->nm_acregmin, nmp->nm_acregmax, 140236176Speter nmp->nm_acdirmin, nmp->nm_acdirmax); 140336176Speter 140436176Speter if (nfs_acdebug) 140537089Sbde printf("nfs_getattrcache: age = %d; final timeo = %d\n", 140636176Speter (time_second - np->n_attrstamp), timeo); 140736176Speter#endif 140836176Speter 140936176Speter if ((time_second - np->n_attrstamp) >= timeo) { 14101541Srgrimes nfsstats.attrcache_misses++; 14111541Srgrimes return (ENOENT); 14121541Srgrimes } 14131541Srgrimes nfsstats.attrcache_hits++; 14141541Srgrimes if (vap->va_size != np->n_size) { 14151541Srgrimes if (vap->va_type == VREG) { 14161541Srgrimes if (np->n_flag & NMODIFIED) { 14171541Srgrimes if (vap->va_size < np->n_size) 14181541Srgrimes vap->va_size = np->n_size; 14191541Srgrimes else 14201541Srgrimes np->n_size = vap->va_size; 142154480Sdillon } else { 14221541Srgrimes np->n_size = vap->va_size; 142354480Sdillon } 142441026Speter vnode_pager_setsize(vp, np->n_size); 142554480Sdillon } else { 14261541Srgrimes np->n_size = vap->va_size; 142754480Sdillon } 14281541Srgrimes } 14291541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 14301541Srgrimes if (np->n_flag & NCHG) { 14319336Sdfr if (np->n_flag & NACC) 14329336Sdfr vaper->va_atime = np->n_atim; 14339336Sdfr if (np->n_flag & NUPD) 14349336Sdfr vaper->va_mtime = np->n_mtim; 14351541Srgrimes } 14361541Srgrimes return (0); 14371541Srgrimes} 14381541Srgrimes 143913416Sphk#ifndef NFS_NOSERVER 14401541Srgrimes/* 144127446Sdfr * Set up nameidata for a lookup() call and do it. 144227446Sdfr * 144327446Sdfr * If pubflag is set, this call is done for a lookup operation on the 144427446Sdfr * public filehandle. In that case we allow crossing mountpoints and 144527446Sdfr * absolute pathnames. However, the caller is expected to check that 144627446Sdfr * the lookup result is within the public fs, and deny access if 144727446Sdfr * it is not. 144848125Sjulian * 144948125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 145048125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 145148125Sjulian * error occurs but the parent was not requested. 145248125Sjulian * 145348125Sjulian * dirp may be set whether an error is returned or not, and must be 145448125Sjulian * released by the caller. 14551541Srgrimes */ 14561549Srgrimesint 145727446Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 14581541Srgrimes register struct nameidata *ndp; 14591541Srgrimes fhandle_t *fhp; 14601541Srgrimes int len; 14611541Srgrimes struct nfssvc_sock *slp; 146228270Swollman struct sockaddr *nam; 14631541Srgrimes struct mbuf **mdp; 14641541Srgrimes caddr_t *dposp; 14659336Sdfr struct vnode **retdirp; 14661541Srgrimes struct proc *p; 146727446Sdfr int kerbflag, pubflag; 14681541Srgrimes{ 14691541Srgrimes register int i, rem; 14701541Srgrimes register struct mbuf *md; 147127446Sdfr register char *fromcp, *tocp, *cp; 147227446Sdfr struct iovec aiov; 147327446Sdfr struct uio auio; 14741541Srgrimes struct vnode *dp; 147527446Sdfr int error, rdonly, linklen; 14761541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 14771541Srgrimes 14789336Sdfr *retdirp = (struct vnode *)0; 147929653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 148029653Sdyson 14811541Srgrimes /* 14821541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 14831541Srgrimes * and set the various ndp fields appropriately. 14841541Srgrimes */ 14851541Srgrimes fromcp = *dposp; 14861541Srgrimes tocp = cnp->cn_pnbuf; 14871541Srgrimes md = *mdp; 14881541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 14891541Srgrimes for (i = 0; i < len; i++) { 14901541Srgrimes while (rem == 0) { 14911541Srgrimes md = md->m_next; 14921541Srgrimes if (md == NULL) { 14931541Srgrimes error = EBADRPC; 14941541Srgrimes goto out; 14951541Srgrimes } 14961541Srgrimes fromcp = mtod(md, caddr_t); 14971541Srgrimes rem = md->m_len; 14981541Srgrimes } 149927446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 15009336Sdfr error = EACCES; 15011541Srgrimes goto out; 15021541Srgrimes } 15031541Srgrimes *tocp++ = *fromcp++; 15041541Srgrimes rem--; 15051541Srgrimes } 15061541Srgrimes *tocp = '\0'; 15071541Srgrimes *mdp = md; 15081541Srgrimes *dposp = fromcp; 15091541Srgrimes len = nfsm_rndup(len)-len; 15101541Srgrimes if (len > 0) { 15111541Srgrimes if (rem >= len) 15121541Srgrimes *dposp += len; 151327609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 15149336Sdfr goto out; 15151541Srgrimes } 151627446Sdfr 15171541Srgrimes /* 15181541Srgrimes * Extract and set starting directory. 15191541Srgrimes */ 152027446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 152127446Sdfr nam, &rdonly, kerbflag, pubflag); 152227446Sdfr if (error) 15231541Srgrimes goto out; 15241541Srgrimes if (dp->v_type != VDIR) { 152517761Sdyson vrele(dp); 15261541Srgrimes error = ENOTDIR; 15271541Srgrimes goto out; 15281541Srgrimes } 152927446Sdfr 153027446Sdfr if (rdonly) 153127446Sdfr cnp->cn_flags |= RDONLY; 153227446Sdfr 153348125Sjulian /* 153448125Sjulian * Set return directory. Reference to dp is implicitly transfered 153548125Sjulian * to the returned pointer 153648125Sjulian */ 153727609Sdfr *retdirp = dp; 153827609Sdfr 153927446Sdfr if (pubflag) { 154027446Sdfr /* 154127446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 154227446Sdfr * and the 'native path' indicator. 154327446Sdfr */ 154429653Sdyson cp = zalloc(namei_zone); 154527446Sdfr fromcp = cnp->cn_pnbuf; 154627446Sdfr tocp = cp; 154727446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 154827446Sdfr switch ((unsigned char)*fromcp) { 154927446Sdfr case WEBNFS_NATIVE_CHAR: 155027446Sdfr /* 155127446Sdfr * 'Native' path for us is the same 155227446Sdfr * as a path according to the NFS spec, 155327446Sdfr * just skip the escape char. 155427446Sdfr */ 155527446Sdfr fromcp++; 155627446Sdfr break; 155727446Sdfr /* 155827446Sdfr * More may be added in the future, range 0x80-0xff 155927446Sdfr */ 156027446Sdfr default: 156127446Sdfr error = EIO; 156229653Sdyson zfree(namei_zone, cp); 156327446Sdfr goto out; 156427446Sdfr } 156527446Sdfr } 156627446Sdfr /* 156727446Sdfr * Translate the '%' escapes, URL-style. 156827446Sdfr */ 156927446Sdfr while (*fromcp != '\0') { 157027446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 157127446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 157227446Sdfr fromcp++; 157327446Sdfr *tocp++ = HEXSTRTOI(fromcp); 157427446Sdfr fromcp += 2; 157527446Sdfr continue; 157627446Sdfr } else { 157727446Sdfr error = ENOENT; 157829653Sdyson zfree(namei_zone, cp); 157927446Sdfr goto out; 158027446Sdfr } 158127446Sdfr } else 158227446Sdfr *tocp++ = *fromcp++; 158327446Sdfr } 158427446Sdfr *tocp = '\0'; 158529653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 158627446Sdfr cnp->cn_pnbuf = cp; 158727446Sdfr } 158827446Sdfr 158927446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 159027446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 159127446Sdfr 159227446Sdfr if (pubflag) { 159327446Sdfr ndp->ni_rootdir = rootvnode; 159427446Sdfr ndp->ni_loopcnt = 0; 159527446Sdfr if (cnp->cn_pnbuf[0] == '/') 159627446Sdfr dp = rootvnode; 159727446Sdfr } else { 159827609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 159927446Sdfr } 160027446Sdfr 160148125Sjulian /* 160248125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 160348125Sjulian * becuase lookup() will dereference ni_startdir. 160448125Sjulian */ 160548125Sjulian 160627446Sdfr cnp->cn_proc = p; 16079336Sdfr VREF(dp); 160848125Sjulian ndp->ni_startdir = dp; 160927446Sdfr 161048125Sjulian for (;;) { 161148125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 161248125Sjulian /* 161348125Sjulian * Call lookup() to do the real work. If an error occurs, 161448125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 161548125Sjulian * we do not have to dereference anything before returning. 161648125Sjulian * In either case ni_startdir will be dereferenced and NULLed 161748125Sjulian * out. 161848125Sjulian */ 161948125Sjulian error = lookup(ndp); 162048125Sjulian if (error) 162148125Sjulian break; 162248125Sjulian 162348125Sjulian /* 162448125Sjulian * Check for encountering a symbolic link. Trivial 162548125Sjulian * termination occurs if no symlink encountered. 162648125Sjulian * Note: zfree is safe because error is 0, so we will 162748125Sjulian * not zfree it again when we break. 162848125Sjulian */ 162948125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 163048125Sjulian nfsrv_object_create(ndp->ni_vp); 163148125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 163248125Sjulian cnp->cn_flags |= HASBUF; 163348125Sjulian else 163448125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 163548125Sjulian break; 163627446Sdfr } 163748125Sjulian 163848125Sjulian /* 163948125Sjulian * Validate symlink 164048125Sjulian */ 16411541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 164227446Sdfr VOP_UNLOCK(ndp->ni_dvp, 0, p); 164327446Sdfr if (!pubflag) { 164427446Sdfr error = EINVAL; 164548125Sjulian goto badlink2; 164627446Sdfr } 164727446Sdfr 164827446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 164927446Sdfr error = ELOOP; 165048125Sjulian goto badlink2; 165127446Sdfr } 165227609Sdfr if (ndp->ni_pathlen > 1) 165329653Sdyson cp = zalloc(namei_zone); 16541541Srgrimes else 165527446Sdfr cp = cnp->cn_pnbuf; 165627446Sdfr aiov.iov_base = cp; 165727446Sdfr aiov.iov_len = MAXPATHLEN; 165827446Sdfr auio.uio_iov = &aiov; 165927446Sdfr auio.uio_iovcnt = 1; 166027446Sdfr auio.uio_offset = 0; 166127446Sdfr auio.uio_rw = UIO_READ; 166227446Sdfr auio.uio_segflg = UIO_SYSSPACE; 166327446Sdfr auio.uio_procp = (struct proc *)0; 166427446Sdfr auio.uio_resid = MAXPATHLEN; 166527446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 166627446Sdfr if (error) { 166748125Sjulian badlink1: 166827446Sdfr if (ndp->ni_pathlen > 1) 166929653Sdyson zfree(namei_zone, cp); 167048125Sjulian badlink2: 167148125Sjulian vrele(ndp->ni_dvp); 167248125Sjulian vput(ndp->ni_vp); 167327446Sdfr break; 167427446Sdfr } 167527446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 167627446Sdfr if (linklen == 0) { 167727446Sdfr error = ENOENT; 167848125Sjulian goto badlink1; 167927446Sdfr } 168027446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 168127446Sdfr error = ENAMETOOLONG; 168248125Sjulian goto badlink1; 168327446Sdfr } 168448125Sjulian 168548125Sjulian /* 168648125Sjulian * Adjust or replace path 168748125Sjulian */ 168827446Sdfr if (ndp->ni_pathlen > 1) { 168927446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 169029653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 169127446Sdfr cnp->cn_pnbuf = cp; 169227446Sdfr } else 169327446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 169427446Sdfr ndp->ni_pathlen += linklen; 169548125Sjulian 169627446Sdfr /* 169748125Sjulian * Cleanup refs for next loop and check if root directory 169848125Sjulian * should replace current directory. Normally ni_dvp 169948125Sjulian * becomes the new base directory and is cleaned up when 170048125Sjulian * we loop. Explicitly null pointers after invalidation 170148125Sjulian * to clarify operation. 170227446Sdfr */ 170348125Sjulian vput(ndp->ni_vp); 170448125Sjulian ndp->ni_vp = NULL; 170548125Sjulian 170627446Sdfr if (cnp->cn_pnbuf[0] == '/') { 170748125Sjulian vrele(ndp->ni_dvp); 170848125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 170948125Sjulian VREF(ndp->ni_dvp); 171027446Sdfr } 171148125Sjulian ndp->ni_startdir = ndp->ni_dvp; 171248125Sjulian ndp->ni_dvp = NULL; 17131541Srgrimes } 171448125Sjulian 171548125Sjulian /* 171648125Sjulian * nfs_namei() guarentees that fields will not contain garbage 171748125Sjulian * whether an error occurs or not. This allows the caller to track 171848125Sjulian * cleanup state trivially. 171948125Sjulian */ 17201541Srgrimesout: 172148125Sjulian if (error) { 172248125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 172348125Sjulian ndp->ni_vp = NULL; 172448125Sjulian ndp->ni_dvp = NULL; 172548125Sjulian ndp->ni_startdir = NULL; 172648125Sjulian cnp->cn_flags &= ~HASBUF; 172748125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 172848125Sjulian ndp->ni_dvp = NULL; 172948125Sjulian } 17301541Srgrimes return (error); 17311541Srgrimes} 17321541Srgrimes 17331541Srgrimes/* 17341541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 17351541Srgrimes * boundary and only trims off the back end 17361541Srgrimes */ 17371541Srgrimesvoid 17381541Srgrimesnfsm_adj(mp, len, nul) 17391541Srgrimes struct mbuf *mp; 17401541Srgrimes register int len; 17411541Srgrimes int nul; 17421541Srgrimes{ 17431541Srgrimes register struct mbuf *m; 17441541Srgrimes register int count, i; 17451541Srgrimes register char *cp; 17461541Srgrimes 17471541Srgrimes /* 17481541Srgrimes * Trim from tail. Scan the mbuf chain, 17491541Srgrimes * calculating its length and finding the last mbuf. 17501541Srgrimes * If the adjustment only affects this mbuf, then just 17511541Srgrimes * adjust and return. Otherwise, rescan and truncate 17521541Srgrimes * after the remaining size. 17531541Srgrimes */ 17541541Srgrimes count = 0; 17551541Srgrimes m = mp; 17561541Srgrimes for (;;) { 17571541Srgrimes count += m->m_len; 17581541Srgrimes if (m->m_next == (struct mbuf *)0) 17591541Srgrimes break; 17601541Srgrimes m = m->m_next; 17611541Srgrimes } 17621541Srgrimes if (m->m_len > len) { 17631541Srgrimes m->m_len -= len; 17641541Srgrimes if (nul > 0) { 17651541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 17661541Srgrimes for (i = 0; i < nul; i++) 17671541Srgrimes *cp++ = '\0'; 17681541Srgrimes } 17691541Srgrimes return; 17701541Srgrimes } 17711541Srgrimes count -= len; 17721541Srgrimes if (count < 0) 17731541Srgrimes count = 0; 17741541Srgrimes /* 17751541Srgrimes * Correct length for chain is "count". 17761541Srgrimes * Find the mbuf with last data, adjust its length, 17771541Srgrimes * and toss data from remaining mbufs on chain. 17781541Srgrimes */ 17791541Srgrimes for (m = mp; m; m = m->m_next) { 17801541Srgrimes if (m->m_len >= count) { 17811541Srgrimes m->m_len = count; 17821541Srgrimes if (nul > 0) { 17831541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 17841541Srgrimes for (i = 0; i < nul; i++) 17851541Srgrimes *cp++ = '\0'; 17861541Srgrimes } 17871541Srgrimes break; 17881541Srgrimes } 17891541Srgrimes count -= m->m_len; 17901541Srgrimes } 17913305Sphk for (m = m->m_next;m;m = m->m_next) 17921541Srgrimes m->m_len = 0; 17931541Srgrimes} 17941541Srgrimes 17951541Srgrimes/* 17969336Sdfr * Make these functions instead of macros, so that the kernel text size 17979336Sdfr * doesn't get too big... 17989336Sdfr */ 17999336Sdfrvoid 18009336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 18019336Sdfr struct nfsrv_descript *nfsd; 18029336Sdfr int before_ret; 18039336Sdfr register struct vattr *before_vap; 18049336Sdfr int after_ret; 18059336Sdfr struct vattr *after_vap; 18069336Sdfr struct mbuf **mbp; 18079336Sdfr char **bposp; 18089336Sdfr{ 18099336Sdfr register struct mbuf *mb = *mbp, *mb2; 18109336Sdfr register char *bpos = *bposp; 181136541Speter register u_int32_t *tl; 18129336Sdfr 18139336Sdfr if (before_ret) { 181436541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 18159336Sdfr *tl = nfs_false; 18169336Sdfr } else { 181736541Speter nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 18189336Sdfr *tl++ = nfs_true; 181947751Speter txdr_hyper(before_vap->va_size, tl); 18209336Sdfr tl += 2; 18219336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 18229336Sdfr tl += 2; 18239336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 18249336Sdfr } 18259336Sdfr *bposp = bpos; 18269336Sdfr *mbp = mb; 18279336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 18289336Sdfr} 18299336Sdfr 18309336Sdfrvoid 18319336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 18329336Sdfr struct nfsrv_descript *nfsd; 18339336Sdfr int after_ret; 18349336Sdfr struct vattr *after_vap; 18359336Sdfr struct mbuf **mbp; 18369336Sdfr char **bposp; 18379336Sdfr{ 18389336Sdfr register struct mbuf *mb = *mbp, *mb2; 18399336Sdfr register char *bpos = *bposp; 184036541Speter register u_int32_t *tl; 18419336Sdfr register struct nfs_fattr *fp; 18429336Sdfr 18439336Sdfr if (after_ret) { 184436541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 18459336Sdfr *tl = nfs_false; 18469336Sdfr } else { 184736541Speter nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 18489336Sdfr *tl++ = nfs_true; 18499336Sdfr fp = (struct nfs_fattr *)tl; 18509336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 18519336Sdfr } 18529336Sdfr *mbp = mb; 18539336Sdfr *bposp = bpos; 18549336Sdfr} 18559336Sdfr 18569336Sdfrvoid 18579336Sdfrnfsm_srvfattr(nfsd, vap, fp) 18589336Sdfr register struct nfsrv_descript *nfsd; 18599336Sdfr register struct vattr *vap; 18609336Sdfr register struct nfs_fattr *fp; 18619336Sdfr{ 18629336Sdfr 18639336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 18649336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 18659336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 18669336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 18679336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 18689336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 186947751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 187047751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 187147028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 187247028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 18739336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 18749336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 18759336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 18769336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 18779336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 18789336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 18799336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 18809336Sdfr } else { 18819336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 18829336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 18839336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 18849336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 18859336Sdfr if (vap->va_type == VFIFO) 18869336Sdfr fp->fa2_rdev = 0xffffffff; 18879336Sdfr else 18889336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 18899336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 18909336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 18919336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 18929336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 18939336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 18949336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 18959336Sdfr } 18969336Sdfr} 18979336Sdfr 18989336Sdfr/* 18991541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 19001541Srgrimes * - look up fsid in mount list (if not found ret error) 19011541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 19021541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 19031541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 19041541Srgrimes */ 19051549Srgrimesint 190627446Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 19071541Srgrimes fhandle_t *fhp; 19081541Srgrimes int lockflag; 19091541Srgrimes struct vnode **vpp; 19101541Srgrimes struct ucred *cred; 19111541Srgrimes struct nfssvc_sock *slp; 191228270Swollman struct sockaddr *nam; 19131541Srgrimes int *rdonlyp; 19149336Sdfr int kerbflag; 191527446Sdfr int pubflag; 19161541Srgrimes{ 191722521Sdyson struct proc *p = curproc; /* XXX */ 19181541Srgrimes register struct mount *mp; 19191541Srgrimes register int i; 19201541Srgrimes struct ucred *credanon; 19211541Srgrimes int error, exflags; 192236534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 192336534Speter struct sockaddr_int *saddr; 192436534Speter#endif 19251541Srgrimes 19261541Srgrimes *vpp = (struct vnode *)0; 192727446Sdfr 192827446Sdfr if (nfs_ispublicfh(fhp)) { 192927446Sdfr if (!pubflag || !nfs_pub.np_valid) 193027446Sdfr return (ESTALE); 193127446Sdfr fhp = &nfs_pub.np_handle; 193227446Sdfr } 193327446Sdfr 193422521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 19353305Sphk if (!mp) 19361541Srgrimes return (ESTALE); 193751138Salfred error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 19383305Sphk if (error) 193951138Salfred return (error); 194051138Salfred error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 194151138Salfred if (error) 19421541Srgrimes return (error); 194336534Speter#ifdef MNT_EXNORESPORT 194436534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 194536534Speter saddr = (struct sockaddr_in *)nam; 194636534Speter if (saddr->sin_family == AF_INET && 194736534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 194836534Speter vput(*vpp); 194954485Sdillon *vpp = NULL; 195036534Speter return (NFSERR_AUTHERR | AUTH_TOOWEAK); 195136534Speter } 195236534Speter } 195336534Speter#endif 19541541Srgrimes /* 19551541Srgrimes * Check/setup credentials. 19561541Srgrimes */ 19571541Srgrimes if (exflags & MNT_EXKERB) { 19589336Sdfr if (!kerbflag) { 19591541Srgrimes vput(*vpp); 196054485Sdillon *vpp = NULL; 19619336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 19621541Srgrimes } 19639336Sdfr } else if (kerbflag) { 19649336Sdfr vput(*vpp); 196554485Sdillon *vpp = NULL; 19669336Sdfr return (NFSERR_AUTHERR | AUTH_TOOWEAK); 19671541Srgrimes } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 19681541Srgrimes cred->cr_uid = credanon->cr_uid; 19691541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 19701541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 19713664Sphk cred->cr_ngroups = i; 19721541Srgrimes } 19731541Srgrimes if (exflags & MNT_EXRDONLY) 19741541Srgrimes *rdonlyp = 1; 19751541Srgrimes else 19761541Srgrimes *rdonlyp = 0; 19777969Sdyson 197817761Sdyson nfsrv_object_create(*vpp); 19797969Sdyson 19801541Srgrimes if (!lockflag) 198122521Sdyson VOP_UNLOCK(*vpp, 0, p); 19821541Srgrimes return (0); 19831541Srgrimes} 19841541Srgrimes 198527446Sdfr 198627446Sdfr/* 198727446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 198827446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 198927446Sdfr * transformed this to all zeroes in both cases, so check for it. 199027446Sdfr */ 199127446Sdfrint 199227446Sdfrnfs_ispublicfh(fhp) 199327446Sdfr fhandle_t *fhp; 199427446Sdfr{ 199527446Sdfr char *cp = (char *)fhp; 199627446Sdfr int i; 199727446Sdfr 199827446Sdfr for (i = 0; i < NFSX_V3FH; i++) 199927446Sdfr if (*cp++ != 0) 200027446Sdfr return (FALSE); 200127446Sdfr return (TRUE); 200227446Sdfr} 200327446Sdfr 200413416Sphk#endif /* NFS_NOSERVER */ 20051541Srgrimes/* 20061541Srgrimes * This function compares two net addresses by family and returns TRUE 20071541Srgrimes * if they are the same host. 20081541Srgrimes * If there is any doubt, return FALSE. 20091541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 20101541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 20111541Srgrimes */ 20121549Srgrimesint 20131541Srgrimesnetaddr_match(family, haddr, nam) 20141541Srgrimes int family; 20151541Srgrimes union nethostaddr *haddr; 201628270Swollman struct sockaddr *nam; 20171541Srgrimes{ 20181541Srgrimes register struct sockaddr_in *inetaddr; 20191541Srgrimes 20201541Srgrimes switch (family) { 20211541Srgrimes case AF_INET: 202228270Swollman inetaddr = (struct sockaddr_in *)nam; 20231541Srgrimes if (inetaddr->sin_family == AF_INET && 20241541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 20251541Srgrimes return (1); 20261541Srgrimes break; 20271541Srgrimes default: 20281541Srgrimes break; 20291541Srgrimes }; 20301541Srgrimes return (0); 20311541Srgrimes} 20325455Sdg 203343305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 20349336Sdfr/* 20359336Sdfr * This function finds the directory cookie that corresponds to the 20369336Sdfr * logical byte offset given. 20379336Sdfr */ 20389336Sdfrnfsuint64 * 20399336Sdfrnfs_getcookie(np, off, add) 20409336Sdfr register struct nfsnode *np; 20419336Sdfr off_t off; 20429336Sdfr int add; 20439336Sdfr{ 20449336Sdfr register struct nfsdmap *dp, *dp2; 20459336Sdfr register int pos; 20469336Sdfr 204736979Sbde pos = (uoff_t)off / NFS_DIRBLKSIZ; 204836979Sbde if (pos == 0 || off < 0) { 20499336Sdfr#ifdef DIAGNOSTIC 20509336Sdfr if (add) 205136979Sbde panic("nfs getcookie add at <= 0"); 20529336Sdfr#endif 20539336Sdfr return (&nfs_nullcookie); 20549336Sdfr } 20559336Sdfr pos--; 20569336Sdfr dp = np->n_cookies.lh_first; 20579336Sdfr if (!dp) { 20589336Sdfr if (add) { 20599336Sdfr MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 20609336Sdfr M_NFSDIROFF, M_WAITOK); 20619336Sdfr dp->ndm_eocookie = 0; 20629336Sdfr LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 20639336Sdfr } else 20649336Sdfr return ((nfsuint64 *)0); 20659336Sdfr } 20669336Sdfr while (pos >= NFSNUMCOOKIES) { 20679336Sdfr pos -= NFSNUMCOOKIES; 20689336Sdfr if (dp->ndm_list.le_next) { 20699336Sdfr if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 20709336Sdfr pos >= dp->ndm_eocookie) 20719336Sdfr return ((nfsuint64 *)0); 20729336Sdfr dp = dp->ndm_list.le_next; 20739336Sdfr } else if (add) { 20749336Sdfr MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 20759336Sdfr M_NFSDIROFF, M_WAITOK); 20769336Sdfr dp2->ndm_eocookie = 0; 20779336Sdfr LIST_INSERT_AFTER(dp, dp2, ndm_list); 20789336Sdfr dp = dp2; 20799336Sdfr } else 20809336Sdfr return ((nfsuint64 *)0); 20819336Sdfr } 20829336Sdfr if (pos >= dp->ndm_eocookie) { 20839336Sdfr if (add) 20849336Sdfr dp->ndm_eocookie = pos + 1; 20859336Sdfr else 20869336Sdfr return ((nfsuint64 *)0); 20879336Sdfr } 20889336Sdfr return (&dp->ndm_cookies[pos]); 20899336Sdfr} 20909336Sdfr 20919336Sdfr/* 20929336Sdfr * Invalidate cached directory information, except for the actual directory 20939336Sdfr * blocks (which are invalidated separately). 20949336Sdfr * Done mainly to avoid the use of stale offset cookies. 20959336Sdfr */ 20969336Sdfrvoid 20979336Sdfrnfs_invaldir(vp) 20989336Sdfr register struct vnode *vp; 20999336Sdfr{ 21009336Sdfr register struct nfsnode *np = VTONFS(vp); 21019336Sdfr 21029336Sdfr#ifdef DIAGNOSTIC 21039336Sdfr if (vp->v_type != VDIR) 21049336Sdfr panic("nfs: invaldir not dir"); 21059336Sdfr#endif 21069336Sdfr np->n_direofoffset = 0; 21079336Sdfr np->n_cookieverf.nfsuquad[0] = 0; 21089336Sdfr np->n_cookieverf.nfsuquad[1] = 0; 21099336Sdfr if (np->n_cookies.lh_first) 21109336Sdfr np->n_cookies.lh_first->ndm_eocookie = 0; 21119336Sdfr} 21129336Sdfr 21139336Sdfr/* 21149336Sdfr * The write verifier has changed (probably due to a server reboot), so all 21159336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 21169336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 211754480Sdillon * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 211854480Sdillon * mount point. 211954480Sdillon * 212054480Sdillon * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 212154480Sdillon * writes are not clusterable. 21229336Sdfr */ 21239336Sdfrvoid 21249336Sdfrnfs_clearcommit(mp) 21259336Sdfr struct mount *mp; 21269336Sdfr{ 21279336Sdfr register struct vnode *vp, *nvp; 21289336Sdfr register struct buf *bp, *nbp; 21299336Sdfr int s; 21309336Sdfr 21319336Sdfr s = splbio(); 21329336Sdfrloop: 21339336Sdfr for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 21349336Sdfr if (vp->v_mount != mp) /* Paranoia */ 21359336Sdfr goto loop; 21369336Sdfr nvp = vp->v_mntvnodes.le_next; 213740790Speter for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 213840790Speter nbp = TAILQ_NEXT(bp, b_vnbufs); 213948225Smckusick if (BUF_REFCNT(bp) == 0 && 214048225Smckusick (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 21419336Sdfr == (B_DELWRI | B_NEEDCOMMIT)) 214254480Sdillon bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 21439336Sdfr } 21449336Sdfr } 21459336Sdfr splx(s); 21469336Sdfr} 21479336Sdfr 214813416Sphk#ifndef NFS_NOSERVER 21499336Sdfr/* 21509336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 21519336Sdfr * numbers not specified for the associated procedure. 21529336Sdfr */ 21535455Sdgint 21549336Sdfrnfsrv_errmap(nd, err) 21559336Sdfr struct nfsrv_descript *nd; 21569336Sdfr register int err; 21579336Sdfr{ 21589336Sdfr register short *defaulterrp, *errp; 21599336Sdfr 21609336Sdfr if (nd->nd_flag & ND_NFSV3) { 21619336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 21629336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 21639336Sdfr while (*++errp) { 21649336Sdfr if (*errp == err) 21659336Sdfr return (err); 21669336Sdfr else if (*errp > err) 21679336Sdfr break; 21689336Sdfr } 21699336Sdfr return ((int)*defaulterrp); 21709336Sdfr } else 21719336Sdfr return (err & 0xffff); 21729336Sdfr } 21739336Sdfr if (err <= ELAST) 21749336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 21759336Sdfr return (NFSERR_IO); 21769336Sdfr} 21779336Sdfr 21789336Sdfrint 217931886Sbdenfsrv_object_create(vp) 218031886Sbde struct vnode *vp; 218131886Sbde{ 21825455Sdg 218331886Sbde if (vp == NULL || vp->v_type != VREG) 218431886Sbde return (1); 218531886Sbde return (vfs_object_create(vp, curproc, 218642315Seivind curproc ? curproc->p_ucred : NULL)); 21875455Sdg} 218836503Speter 218936503Speter/* 219036503Speter * Sort the group list in increasing numerical order. 219136503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 219236503Speter * that used to be here.) 219336503Speter */ 219436503Spetervoid 219536503Speternfsrvw_sort(list, num) 219636503Speter register gid_t *list; 219736503Speter register int num; 219836503Speter{ 219936503Speter register int i, j; 220036503Speter gid_t v; 220136503Speter 220236503Speter /* Insertion sort. */ 220336503Speter for (i = 1; i < num; i++) { 220436503Speter v = list[i]; 220536503Speter /* find correct slot for value v, moving others up */ 220636503Speter for (j = i; --j >= 0 && v < list[j];) 220736503Speter list[j + 1] = list[j]; 220836503Speter list[j + 1] = v; 220936503Speter } 221036503Speter} 221136503Speter 221236503Speter/* 221336503Speter * copy credentials making sure that the result can be compared with bcmp(). 221436503Speter */ 221536503Spetervoid 221636503Speternfsrv_setcred(incred, outcred) 221736503Speter register struct ucred *incred, *outcred; 221836503Speter{ 221936503Speter register int i; 222036503Speter 222136503Speter bzero((caddr_t)outcred, sizeof (struct ucred)); 222236503Speter outcred->cr_ref = 1; 222336503Speter outcred->cr_uid = incred->cr_uid; 222436503Speter outcred->cr_ngroups = incred->cr_ngroups; 222536503Speter for (i = 0; i < incred->cr_ngroups; i++) 222636503Speter outcred->cr_groups[i] = incred->cr_groups[i]; 222736503Speter nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 222836503Speter} 222913416Sphk#endif /* NFS_NOSERVER */ 2230