nfs_srvsubs.c revision 60833
1139823Simp/* 2200838Sluigi * Copyright (c) 1989, 1993 398943Sluigi * The Regents of the University of California. All rights reserved. 498943Sluigi * 598943Sluigi * This code is derived from software contributed to Berkeley by 698943Sluigi * Rick Macklem at The University of Guelph. 798943Sluigi * 898943Sluigi * Redistribution and use in source and binary forms, with or without 9116763Sluigi * modification, are permitted provided that the following conditions 1098943Sluigi * are met: 1198943Sluigi * 1. Redistributions of source code must retain the above copyright 12105775Smaxim * notice, this list of conditions and the following disclaimer. 1398943Sluigi * 2. Redistributions in binary form must reproduce the above copyright 1498943Sluigi * notice, this list of conditions and the following disclaimer in the 1598943Sluigi * documentation and/or other materials provided with the distribution. 1698943Sluigi * 3. All advertising materials mentioning features or use of this software 1798943Sluigi * must display the following acknowledgement: 1898943Sluigi * This product includes software developed by the University of 1998943Sluigi * California, Berkeley and its contributors. 2098943Sluigi * 4. Neither the name of the University nor the names of its contributors 2198943Sluigi * may be used to endorse or promote products derived from this software 2298943Sluigi * without specific prior written permission. 2398943Sluigi * 2498943Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2598943Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26172467Ssilby * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27172467Ssilby * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28172467Ssilby * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2998943Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30200601Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3198943Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3298943Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33225518Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34166479Salc * SUCH DAMAGE. 3598943Sluigi * 3698943Sluigi * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 3798943Sluigi * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 60833 2000-05-23 20:41:01Z jake $ 3898943Sluigi */ 39152928Sume 40152928Sume/* 4198943Sluigi * These functions support the macros and help fiddle mbuf chains for 4298943Sluigi * the nfs op functions. They do things like create the rpc header and 4398943Sluigi * copy data between mbuf chains and uio lists. 44138642Scsjp */ 45165648Spiso#include <sys/param.h> 4698943Sluigi#include <sys/systm.h> 4798943Sluigi#include <sys/kernel.h> 4898943Sluigi#include <sys/bio.h> 49155201Scsjp#include <sys/buf.h> 50133600Scsjp#include <sys/proc.h> 51129876Sphk#include <sys/mount.h> 52164033Srwatson#include <sys/vnode.h> 5398943Sluigi#include <sys/namei.h> 54155201Scsjp#include <sys/mbuf.h> 5598943Sluigi#include <sys/socket.h> 5698943Sluigi#include <sys/stat.h> 5798943Sluigi#include <sys/malloc.h> 5898943Sluigi#include <sys/sysent.h> 5998943Sluigi#include <sys/syscall.h> 60188676Sluigi 6198943Sluigi#include <vm/vm.h> 6298943Sluigi#include <vm/vm_object.h> 63171173Smlaier#include <vm/vm_extern.h> 64243586Sae#include <vm/vm_zone.h> 65185571Sbz 66175659Srwatson#include <nfs/rpcv2.h> 6798943Sluigi#include <nfs/nfsproto.h> 6898943Sluigi#include <nfs/nfs.h> 6998943Sluigi#include <nfs/nfsnode.h> 7098943Sluigi#include <nfs/xdr_subs.h> 7198943Sluigi#include <nfs/nfsm_subs.h> 7298943Sluigi#include <nfs/nfsmount.h> 7398943Sluigi#include <nfs/nqnfs.h> 74163069Sbz#include <nfs/nfsrtt.h> 75161767Sjhay 7698943Sluigi#include <netinet/in.h> 7798943Sluigi 7898943Sluigi/* 79164258Sbz * Data items converted to xdr at startup, since they are constant 80185571Sbz * This is kinda hokey, but may save a little time doing byte swaps 81145246Sbrooks */ 82145246Sbrooksu_int32_t nfs_xdrneg1; 83148414Sumeu_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 84223073Sae rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 85148414Sume rpc_auth_kerb; 86200027Sumeu_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 87148414Sume 88145246Sbrooks/* And other global data */ 89243401Sglebiusstatic u_int32_t nfs_xid = 0; 90243401Sglebiusstatic enum vtype nv2tov_type[8]= { 9199475Sluigi VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9299475Sluigi}; 93188580Sluigienum vtype nv3tov_type[8]= { 94163606Srwatson VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 95188580Sluigi}; 96163606Srwatson 97101628Sluigiint nfs_ticks; 98200601Sluigiint nfs_pbuf_freecnt = -1; /* start out unlimited */ 99200601Sluigi 100101628Sluigistruct nfs_reqq nfs_reqq; 10198943Sluigistruct nfssvc_sockhead nfssvc_sockhead; 102200601Sluigiint nfssvc_sockhead_flag; 103215701Sdimstruct nfsd_head nfsd_head; 104200601Sluigiint nfsd_head_flag; 105195699Srwatsonstruct nfs_bufq nfs_bufq; 106215701Sdimstruct nqtimerhead nqtimerhead; 107200601Sluigistruct nqfhhashhead *nqfhhashtbl; 108200601Sluigiu_long nqfhhash; 109225030Sbz 110225030Sbzstatic void (*nfs_prev_lease_updatetime) __P((int)); 111225030Sbzstatic int nfs_prev_nfssvc_sy_narg; 112191932Sjhbstatic sy_call_t *nfs_prev_nfssvc_sy_call; 113191932Sjhb 114191932Sjhb#ifndef NFS_NOSERVER 115191932Sjhb 116191932Sjhbstatic vop_t *nfs_prev_vop_lease_check; 11798943Sluigi 118200601Sluigi/* 119220878Sbz * Mapping of old NFS Version 2 RPC numbers to generic numbers. 120193859Soleg */ 121234597Smelifaroint nfsv3_procid[NFS_NPROCS] = { 122234597Smelifaro NFSPROC_NULL, 123234597Smelifaro NFSPROC_GETATTR, 124234597Smelifaro NFSPROC_SETATTR, 125130363Scsjp NFSPROC_NOOP, 126200601Sluigi NFSPROC_LOOKUP, 127200601Sluigi NFSPROC_READLINK, 128200601Sluigi NFSPROC_READ, 129200601Sluigi NFSPROC_NOOP, 130200601Sluigi NFSPROC_WRITE, 131200601Sluigi NFSPROC_CREATE, 132200601Sluigi NFSPROC_REMOVE, 13398943Sluigi NFSPROC_RENAME, 134200601Sluigi NFSPROC_LINK, 135200601Sluigi NFSPROC_SYMLINK, 136200601Sluigi NFSPROC_MKDIR, 137200601Sluigi NFSPROC_RMDIR, 138200601Sluigi NFSPROC_READDIR, 139200601Sluigi NFSPROC_FSSTAT, 140200601Sluigi NFSPROC_NOOP, 141200601Sluigi NFSPROC_NOOP, 142200601Sluigi NFSPROC_NOOP, 143195699Srwatson NFSPROC_NOOP, 14498943Sluigi NFSPROC_NOOP, 145176669Spiso NFSPROC_NOOP, 146200580Sluigi NFSPROC_NOOP, 147176669Spiso NFSPROC_NOOP 148176669Spiso}; 149176669Spiso 150176669Spiso#endif /* NFS_NOSERVER */ 15198943Sluigi/* 15298943Sluigi * and the reverse mapping from generic to Version 2 procedure numbers 153204591Sluigi */ 154234597Smelifaroint nfsv2_procid[NFS_NPROCS] = { 155204591Sluigi NFSV2PROC_NULL, 156204591Sluigi NFSV2PROC_GETATTR, 157204591Sluigi NFSV2PROC_SETATTR, 15898943Sluigi NFSV2PROC_LOOKUP, 159200601Sluigi NFSV2PROC_NOOP, 160200601Sluigi NFSV2PROC_READLINK, 161200601Sluigi NFSV2PROC_READ, 162195699Srwatson NFSV2PROC_WRITE, 163195862Sjulian NFSV2PROC_CREATE, 164195862Sjulian NFSV2PROC_MKDIR, 165195699Srwatson NFSV2PROC_SYMLINK, 166195862Sjulian NFSV2PROC_CREATE, 167195862Sjulian NFSV2PROC_REMOVE, 168195699Srwatson NFSV2PROC_RMDIR, 169195699Srwatson NFSV2PROC_RENAME, 170186048Sbz NFSV2PROC_LINK, 171182818Srik NFSV2PROC_READDIR, 172204591Sluigi NFSV2PROC_NOOP, 173195862Sjulian NFSV2PROC_STATFS, 174234597Smelifaro NFSV2PROC_NOOP, 175234597Smelifaro NFSV2PROC_NOOP, 176234597Smelifaro NFSV2PROC_NOOP, 177191932Sjhb NFSV2PROC_NOOP, 178195862Sjulian NFSV2PROC_NOOP, 179195862Sjulian NFSV2PROC_NOOP, 180191932Sjhb NFSV2PROC_NOOP, 181234597Smelifaro}; 182200838Sluigi 183200838Sluigi#ifndef NFS_NOSERVER 184200838Sluigi/* 185200040Sluigi * Maps errno values to nfs error numbers. 186195862Sjulian * Use NFSERR_IO as the catch all for ones not specifically defined in 187195862Sjulian * RFC 1094. 188195862Sjulian */ 189195862Sjulianstatic u_char nfsrv_v2errmap[ELAST] = { 190195862Sjulian NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 191195862Sjulian NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 192225030Sbz NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 193225030Sbz NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 194225030Sbz NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 195200040Sluigi NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 19698943Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 197204591Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 198204591Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 199187821Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20098943Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 201200580Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 202149020Sbz NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 203200601Sluigi NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 204145093Sbrooks NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 205145093Sbrooks NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20698943Sluigi NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 207145093Sbrooks NFSERR_IO /* << Last is 86 */ 208145093Sbrooks}; 209164258Sbz 210145093Sbrooks/* 211145565Sbrooks * Maps errno values to nfs error numbers. 212145246Sbrooks * Although it is not obvious whether or not NFS clients really care if 21398943Sluigi * a returned error value is in the specified list for the procedure, the 21499622Sluigi * safest thing to do is filter them appropriately. For Version 2, the 215145565Sbrooks * X/Open XNFS document is the only specification that defines error values 21698943Sluigi * for each RPC (The RFC simply lists all possible error values for all RPCs), 217145093Sbrooks * so I have decided to not do this for Version 2. 21898943Sluigi * The first entry is the default error return and the rest are the valid 21998943Sluigi * errors for that RPC in increasing numeric order. 22098943Sluigi */ 22198943Sluigistatic short nfsv3err_null[] = { 22298943Sluigi 0, 22398943Sluigi 0, 22498943Sluigi}; 22598943Sluigi 226145565Sbrooksstatic short nfsv3err_getattr[] = { 22798943Sluigi NFSERR_IO, 228145093Sbrooks NFSERR_IO, 229145093Sbrooks NFSERR_STALE, 23098943Sluigi NFSERR_BADHANDLE, 23198943Sluigi NFSERR_SERVERFAULT, 23298943Sluigi 0, 23398943Sluigi}; 23498943Sluigi 23598943Sluigistatic short nfsv3err_setattr[] = { 23698943Sluigi NFSERR_IO, 23798943Sluigi NFSERR_PERM, 23898943Sluigi NFSERR_IO, 23998943Sluigi NFSERR_ACCES, 24098943Sluigi NFSERR_INVAL, 24198943Sluigi NFSERR_NOSPC, 24298943Sluigi NFSERR_ROFS, 24398943Sluigi NFSERR_DQUOT, 24498943Sluigi NFSERR_STALE, 24598943Sluigi NFSERR_BADHANDLE, 24698943Sluigi NFSERR_NOT_SYNC, 24798943Sluigi NFSERR_SERVERFAULT, 24898943Sluigi 0, 24998943Sluigi}; 25098943Sluigi 25198943Sluigistatic short nfsv3err_lookup[] = { 25298943Sluigi NFSERR_IO, 25398943Sluigi NFSERR_NOENT, 25498943Sluigi NFSERR_IO, 25598943Sluigi NFSERR_ACCES, 25698943Sluigi NFSERR_NOTDIR, 25798943Sluigi NFSERR_NAMETOL, 25898943Sluigi NFSERR_STALE, 25998943Sluigi NFSERR_BADHANDLE, 26098943Sluigi NFSERR_SERVERFAULT, 26198943Sluigi 0, 26298943Sluigi}; 26398943Sluigi 26498943Sluigistatic short nfsv3err_access[] = { 26598943Sluigi NFSERR_IO, 26698943Sluigi NFSERR_IO, 26798943Sluigi NFSERR_STALE, 26898943Sluigi NFSERR_BADHANDLE, 26998943Sluigi NFSERR_SERVERFAULT, 27098943Sluigi 0, 27198943Sluigi}; 27298943Sluigi 27398943Sluigistatic short nfsv3err_readlink[] = { 27498943Sluigi NFSERR_IO, 27598943Sluigi NFSERR_IO, 27698943Sluigi NFSERR_ACCES, 27798943Sluigi NFSERR_INVAL, 27898943Sluigi NFSERR_STALE, 27998943Sluigi NFSERR_BADHANDLE, 28098943Sluigi NFSERR_NOTSUPP, 28198943Sluigi NFSERR_SERVERFAULT, 28298943Sluigi 0, 28398943Sluigi}; 28498943Sluigi 28598943Sluigistatic short nfsv3err_read[] = { 28698943Sluigi NFSERR_IO, 28798943Sluigi NFSERR_IO, 28898943Sluigi NFSERR_NXIO, 28998943Sluigi NFSERR_ACCES, 29098943Sluigi NFSERR_INVAL, 29198943Sluigi NFSERR_STALE, 29298943Sluigi NFSERR_BADHANDLE, 29398943Sluigi NFSERR_SERVERFAULT, 29498943Sluigi 0, 29598943Sluigi}; 29698943Sluigi 29798943Sluigistatic short nfsv3err_write[] = { 29898943Sluigi NFSERR_IO, 29998943Sluigi NFSERR_IO, 30098943Sluigi NFSERR_ACCES, 30198943Sluigi NFSERR_INVAL, 30298943Sluigi NFSERR_FBIG, 30398943Sluigi NFSERR_NOSPC, 30498943Sluigi NFSERR_ROFS, 305145093Sbrooks NFSERR_DQUOT, 30698943Sluigi NFSERR_STALE, 30798943Sluigi NFSERR_BADHANDLE, 30898943Sluigi NFSERR_SERVERFAULT, 30998943Sluigi 0, 31098943Sluigi}; 31198943Sluigi 31298943Sluigistatic short nfsv3err_create[] = { 31398943Sluigi NFSERR_IO, 31498943Sluigi NFSERR_IO, 31598943Sluigi NFSERR_ACCES, 31698943Sluigi NFSERR_EXIST, 31798943Sluigi NFSERR_NOTDIR, 31898943Sluigi NFSERR_NOSPC, 31998943Sluigi NFSERR_ROFS, 32098943Sluigi NFSERR_NAMETOL, 32198943Sluigi NFSERR_DQUOT, 32298943Sluigi NFSERR_STALE, 32398943Sluigi NFSERR_BADHANDLE, 32498943Sluigi NFSERR_NOTSUPP, 32598943Sluigi NFSERR_SERVERFAULT, 32698943Sluigi 0, 32798943Sluigi}; 32898943Sluigi 32998943Sluigistatic short nfsv3err_mkdir[] = { 33098943Sluigi NFSERR_IO, 33198943Sluigi NFSERR_IO, 33298943Sluigi NFSERR_ACCES, 33398943Sluigi NFSERR_EXIST, 33498943Sluigi NFSERR_NOTDIR, 33598943Sluigi NFSERR_NOSPC, 33698943Sluigi NFSERR_ROFS, 33798943Sluigi NFSERR_NAMETOL, 33898943Sluigi NFSERR_DQUOT, 33998943Sluigi NFSERR_STALE, 34098943Sluigi NFSERR_BADHANDLE, 34198943Sluigi NFSERR_NOTSUPP, 34298943Sluigi NFSERR_SERVERFAULT, 34398943Sluigi 0, 34498943Sluigi}; 34598943Sluigi 34698943Sluigistatic short nfsv3err_symlink[] = { 34798943Sluigi NFSERR_IO, 34898943Sluigi NFSERR_IO, 34998943Sluigi NFSERR_ACCES, 35098943Sluigi NFSERR_EXIST, 351234597Smelifaro NFSERR_NOTDIR, 35298943Sluigi NFSERR_NOSPC, 35398943Sluigi NFSERR_ROFS, 35498943Sluigi NFSERR_NAMETOL, 35598943Sluigi NFSERR_DQUOT, 35699475Sluigi NFSERR_STALE, 357234597Smelifaro NFSERR_BADHANDLE, 358234597Smelifaro NFSERR_NOTSUPP, 359234597Smelifaro NFSERR_SERVERFAULT, 36098943Sluigi 0, 361121816Sbrooks}; 362121816Sbrooks 363121816Sbrooksstatic short nfsv3err_mknod[] = { 364121816Sbrooks NFSERR_IO, 365121816Sbrooks NFSERR_IO, 366121816Sbrooks NFSERR_ACCES, 367121816Sbrooks NFSERR_EXIST, 36898943Sluigi NFSERR_NOTDIR, 369210120Sluigi NFSERR_NOSPC, 37098943Sluigi NFSERR_ROFS, 37198943Sluigi NFSERR_NAMETOL, 372195023Srwatson NFSERR_DQUOT, 37398943Sluigi NFSERR_STALE, 37498943Sluigi NFSERR_BADHANDLE, 37598943Sluigi NFSERR_NOTSUPP, 37698943Sluigi NFSERR_SERVERFAULT, 377191288Srwatson NFSERR_BADTYPE, 378195023Srwatson 0, 37998943Sluigi}; 380191288Srwatson 38198943Sluigistatic short nfsv3err_remove[] = { 382195023Srwatson NFSERR_IO, 383204591Sluigi NFSERR_NOENT, 38498943Sluigi NFSERR_IO, 38598943Sluigi NFSERR_ACCES, 38698943Sluigi NFSERR_NOTDIR, 38798943Sluigi NFSERR_ROFS, 388112250Scjc NFSERR_NAMETOL, 389128575Sandre NFSERR_STALE, 390128575Sandre NFSERR_BADHANDLE, 391128575Sandre NFSERR_SERVERFAULT, 392112250Scjc 0, 393116763Sluigi}; 394200601Sluigi 395200601Sluigistatic short nfsv3err_rmdir[] = { 396200601Sluigi NFSERR_IO, 397200601Sluigi NFSERR_NOENT, 398200601Sluigi NFSERR_IO, 399200601Sluigi NFSERR_ACCES, 400128575Sandre NFSERR_EXIST, 401112250Scjc NFSERR_NOTDIR, 402112250Scjc NFSERR_INVAL, 403128575Sandre NFSERR_ROFS, 404112250Scjc NFSERR_NAMETOL, 405200601Sluigi NFSERR_NOTEMPTY, 406200601Sluigi NFSERR_STALE, 407200601Sluigi NFSERR_BADHANDLE, 408112250Scjc NFSERR_NOTSUPP, 409112250Scjc NFSERR_SERVERFAULT, 410178888Sjulian 0, 411112250Scjc}; 412204591Sluigi 413204591Sluigistatic short nfsv3err_rename[] = { 414204591Sluigi NFSERR_IO, 415123000Sandre NFSERR_NOENT, 416112250Scjc NFSERR_IO, 417112250Scjc NFSERR_ACCES, 418123000Sandre NFSERR_EXIST, 419123000Sandre NFSERR_XDEV, 420112250Scjc NFSERR_NOTDIR, 421123000Sandre NFSERR_ISDIR, 422123000Sandre NFSERR_INVAL, 423123000Sandre NFSERR_NOSPC, 424186119Sqingli NFSERR_ROFS, 425112250Scjc NFSERR_MLINK, 426122922Sandre NFSERR_NAMETOL, 427112250Scjc NFSERR_NOTEMPTY, 428128575Sandre NFSERR_DQUOT, 429154769Soleg NFSERR_STALE, 430154769Soleg NFSERR_BADHANDLE, 431154769Soleg NFSERR_NOTSUPP, 432154769Soleg NFSERR_SERVERFAULT, 433154769Soleg 0, 434154769Soleg}; 435154769Soleg 436154769Solegstatic short nfsv3err_link[] = { 437122922Sandre NFSERR_IO, 438122922Sandre NFSERR_IO, 439122922Sandre NFSERR_ACCES, 440128575Sandre NFSERR_EXIST, 441128575Sandre NFSERR_XDEV, 442128575Sandre NFSERR_NOTDIR, 443128575Sandre NFSERR_INVAL, 444128575Sandre NFSERR_NOSPC, 445128575Sandre NFSERR_ROFS, 446128575Sandre NFSERR_MLINK, 447128575Sandre NFSERR_NAMETOL, 448132510Sandre NFSERR_DQUOT, 449132510Sandre NFSERR_STALE, 450132510Sandre NFSERR_BADHANDLE, 451132510Sandre NFSERR_NOTSUPP, 452132510Sandre NFSERR_SERVERFAULT, 453132510Sandre 0, 454128575Sandre}; 455122922Sandre 456116981Sluigistatic short nfsv3err_readdir[] = { 457204591Sluigi NFSERR_IO, 458112250Scjc NFSERR_IO, 459112250Scjc NFSERR_ACCES, 460145266Sphk NFSERR_NOTDIR, 461145246Sbrooks NFSERR_STALE, 462145246Sbrooks NFSERR_BADHANDLE, 463145246Sbrooks NFSERR_BAD_COOKIE, 464145246Sbrooks NFSERR_TOOSMALL, 465145246Sbrooks NFSERR_SERVERFAULT, 466145246Sbrooks 0, 467147415Smlaier}; 468145246Sbrooks 469112250Scjcstatic short nfsv3err_readdirplus[] = { 470145246Sbrooks NFSERR_IO, 471145246Sbrooks NFSERR_IO, 472145246Sbrooks NFSERR_ACCES, 473147415Smlaier NFSERR_NOTDIR, 474147415Smlaier NFSERR_STALE, 475147415Smlaier NFSERR_BADHANDLE, 476147415Smlaier NFSERR_BAD_COOKIE, 477147415Smlaier NFSERR_NOTSUPP, 478145246Sbrooks NFSERR_TOOSMALL, 479145246Sbrooks NFSERR_SERVERFAULT, 480145246Sbrooks 0, 481145246Sbrooks}; 482145246Sbrooks 483145246Sbrooksstatic short nfsv3err_fsstat[] = { 484147415Smlaier NFSERR_IO, 485147415Smlaier NFSERR_IO, 486147415Smlaier NFSERR_STALE, 487147415Smlaier NFSERR_BADHANDLE, 488145246Sbrooks NFSERR_SERVERFAULT, 489191288Srwatson 0, 490195023Srwatson}; 491191338Srwatson 492147415Smlaierstatic short nfsv3err_fsinfo[] = { 493147415Smlaier NFSERR_STALE, 494147415Smlaier NFSERR_STALE, 495147415Smlaier NFSERR_BADHANDLE, 496147415Smlaier NFSERR_SERVERFAULT, 497191288Srwatson 0, 498195023Srwatson}; 499147415Smlaier 500191288Srwatsonstatic short nfsv3err_pathconf[] = { 501147415Smlaier NFSERR_STALE, 502147415Smlaier NFSERR_STALE, 503195023Srwatson NFSERR_BADHANDLE, 504191288Srwatson NFSERR_SERVERFAULT, 505147415Smlaier 0, 506145246Sbrooks}; 507145246Sbrooks 508145246Sbrooksstatic short nfsv3err_commit[] = { 509232292Sbz NFSERR_IO, 510145246Sbrooks NFSERR_IO, 511147418Smlaier NFSERR_STALE, 512147415Smlaier NFSERR_BADHANDLE, 513145246Sbrooks NFSERR_SERVERFAULT, 514147418Smlaier 0, 515147418Smlaier}; 516147415Smlaier 517147418Smlaierstatic short *nfsrv_v3errmap[] = { 518147418Smlaier nfsv3err_null, 519147418Smlaier nfsv3err_getattr, 520145246Sbrooks nfsv3err_setattr, 521232292Sbz nfsv3err_lookup, 522147418Smlaier nfsv3err_access, 523147418Smlaier nfsv3err_readlink, 524147418Smlaier nfsv3err_read, 525152288Ssuz nfsv3err_write, 526152288Ssuz nfsv3err_create, 527152288Ssuz nfsv3err_mkdir, 528152288Ssuz nfsv3err_symlink, 529152288Ssuz nfsv3err_mknod, 530152288Ssuz nfsv3err_remove, 531152288Ssuz nfsv3err_rmdir, 532152288Ssuz nfsv3err_rename, 533147418Smlaier nfsv3err_link, 534147418Smlaier nfsv3err_readdir, 535147415Smlaier nfsv3err_readdirplus, 536147418Smlaier nfsv3err_fsstat, 537147418Smlaier nfsv3err_fsinfo, 538147418Smlaier nfsv3err_pathconf, 539147418Smlaier nfsv3err_commit, 540147418Smlaier}; 541147415Smlaier 542147418Smlaier#endif /* NFS_NOSERVER */ 543147418Smlaier 544147418Smlaierextern struct nfsrtt nfsrtt; 545147418Smlaierextern time_t nqnfsstarttime; 546147418Smlaierextern int nqsrv_clockskew; 547147418Smlaierextern int nqsrv_writeslack; 548147418Smlaierextern int nqsrv_maxlease; 549147418Smlaierextern struct nfsstats nfsstats; 550147418Smlaierextern int nqnfs_piggy[NFS_NPROCS]; 551147418Smlaierextern nfstype nfsv2_type[9]; 552147415Smlaierextern nfstype nfsv3_type[9]; 553147418Smlaierextern struct nfsnodehashhead *nfsnodehashtbl; 554145246Sbrooksextern u_long nfsnodehash; 555200601Sluigi 556149020Sbzstruct nfssvc_args; 557149020Sbzextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 558149020Sbz 559149020SbzLIST_HEAD(nfsnodehashhead, struct nfsnode); 560149020Sbz 561149020Sbzint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 562149020Sbz 563149020Sbzu_quad_t 564149020Sbznfs_curusec() 565149020Sbz{ 566149020Sbz struct timeval tv; 567149020Sbz 568149020Sbz getmicrotime(&tv); 569149020Sbz return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); 570149020Sbz} 571165738Sjulian 572149020Sbz/* 573165738Sjulian * Create the header for an rpc request packet 574165738Sjulian * The hsiz is the size of the rest of the nfs request header. 575165738Sjulian * (just used to decide if a cluster is a good idea) 576160025Sbz */ 577149020Sbzstruct mbuf * 578165738Sjuliannfsm_reqh(vp, procid, hsiz, bposp) 579149020Sbz struct vnode *vp; 580200027Sume u_long procid; 581200027Sume int hsiz; 582200601Sluigi caddr_t *bposp; 583200027Sume{ 584200027Sume register struct mbuf *mb; 585200027Sume register u_int32_t *tl; 586200027Sume register caddr_t bpos; 587200027Sume struct mbuf *mb2; 588149020Sbz struct nfsmount *nmp; 589201527Sluigi int nqflag; 590149020Sbz 591165738Sjulian MGET(mb, M_WAIT, MT_DATA); 592165738Sjulian if (hsiz >= MINCLSIZE) 593165738Sjulian MCLGET(mb, M_WAIT); 594165738Sjulian mb->m_len = 0; 595165738Sjulian bpos = mtod(mb, caddr_t); 596165738Sjulian 597165738Sjulian /* 598165738Sjulian * For NQNFS, add lease request. 599165738Sjulian */ 600165738Sjulian if (vp) { 601165738Sjulian nmp = VFSTONFS(vp->v_mount); 602165738Sjulian if (nmp->nm_flag & NFSMNT_NQNFS) { 603165738Sjulian nqflag = NQNFS_NEEDLEASE(vp, procid); 604149020Sbz if (nqflag) { 605201527Sluigi nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 606149020Sbz *tl++ = txdr_unsigned(nqflag); 607149020Sbz *tl = txdr_unsigned(nmp->nm_leaseterm); 608149020Sbz } else { 609149020Sbz nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 610145266Sphk *tl = 0; 611145266Sphk } 61298943Sluigi } 61398943Sluigi } 61498943Sluigi /* Finally, return values */ 61598943Sluigi *bposp = bpos; 61698943Sluigi return (mb); 617201122Sluigi} 61898943Sluigi 619101843Sphk/* 620165738Sjulian * Build the RPC header and fill in the authorization info. 621165738Sjulian * The authorization string argument is only used when the credentials 622165738Sjulian * come from outside of the kernel. 623165738Sjulian * Returns the head of the mbuf list. 624165738Sjulian */ 625165738Sjulianstruct mbuf * 626165738Sjuliannfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 627165738Sjulian verf_str, mrest, mrest_len, mbp, xidp) 628165738Sjulian register struct ucred *cr; 629165738Sjulian int nmflag; 630108327Siedowse int procid; 631108327Siedowse int auth_type; 632201527Sluigi int auth_len; 63399475Sluigi char *auth_str; 634160025Sbz int verf_len; 63599475Sluigi char *verf_str; 63699475Sluigi struct mbuf *mrest; 637147247Sgreen int mrest_len; 638147247Sgreen struct mbuf **mbp; 639200601Sluigi u_int32_t *xidp; 640162238Scsjp{ 641100004Sluigi register struct mbuf *mb; 642147247Sgreen register u_int32_t *tl; 643147247Sgreen register caddr_t bpos; 644147247Sgreen register int i; 645201527Sluigi struct mbuf *mreq, *mb2; 64699475Sluigi int siz, grpsiz, authsiz; 647201527Sluigi 64899475Sluigi authsiz = nfsm_rndup(auth_len); 64998943Sluigi MGETHDR(mb, M_WAIT, MT_DATA); 65098943Sluigi if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 651200601Sluigi MCLGET(mb, M_WAIT); 652200601Sluigi } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 653200601Sluigi MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 654200601Sluigi } else { 655200601Sluigi MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 656200601Sluigi } 657200601Sluigi mb->m_len = 0; 658200601Sluigi mreq = mb; 659200601Sluigi bpos = mtod(mb, caddr_t); 660200601Sluigi 661122265Ssam /* 662223073Sae * First the RPC header. 663223073Sae */ 664122265Ssam nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 665204591Sluigi 666223073Sae /* Get a pretty random xid to start with */ 667204591Sluigi if (!nfs_xid) 668204591Sluigi nfs_xid = random(); 669204591Sluigi /* 670204591Sluigi * Skip zero xid if it should ever happen. 671223073Sae */ 672122265Ssam if (++nfs_xid == 0) 673223073Sae nfs_xid++; 674223073Sae 675223073Sae *tl++ = *xidp = txdr_unsigned(nfs_xid); 676222488Srwatson *tl++ = rpc_call; 677122265Ssam *tl++ = rpc_vers; 678122265Ssam if (nmflag & NFSMNT_NQNFS) { 679223073Sae *tl++ = txdr_unsigned(NQNFS_PROG); 680223073Sae *tl++ = txdr_unsigned(NQNFS_VER3); 681223073Sae } else { 682223073Sae *tl++ = txdr_unsigned(NFS_PROG); 683130363Scsjp if (nmflag & NFSMNT_NFSV3) 684135920Smlaier *tl++ = txdr_unsigned(NFS_VER3); 685135920Smlaier else 686135920Smlaier *tl++ = txdr_unsigned(NFS_VER2); 687135920Smlaier } 688183398Srwatson if (nmflag & NFSMNT_NFSV3) 689178325Srwatson *tl++ = txdr_unsigned(procid); 690135920Smlaier else 691194498Sbrooks *tl++ = txdr_unsigned(nfsv2_procid[procid]); 692183398Srwatson 693183418Srwatson /* 694183418Srwatson * And then the authorization cred. 695135920Smlaier */ 696135920Smlaier *tl++ = txdr_unsigned(auth_type); 697130363Scsjp *tl = txdr_unsigned(authsiz); 698130363Scsjp switch (auth_type) { 699130363Scsjp case RPCAUTH_UNIX: 700130363Scsjp nfsm_build(tl, u_int32_t *, auth_len); 701183398Srwatson *tl++ = 0; /* stamp ?? */ 702130363Scsjp *tl++ = 0; /* NULL hostname */ 703223073Sae *tl++ = txdr_unsigned(cr->cr_uid); 704222488Srwatson *tl++ = txdr_unsigned(cr->cr_groups[0]); 705181803Sbz grpsiz = (auth_len >> 2) - 5; 706223073Sae *tl++ = txdr_unsigned(grpsiz); 707222488Srwatson for (i = 1; i <= grpsiz; i++) 708181803Sbz *tl++ = txdr_unsigned(cr->cr_groups[i]); 709122265Ssam break; 710122265Ssam case RPCAUTH_KERB4: 711222488Srwatson siz = auth_len; 712122265Ssam while (siz > 0) { 713183398Srwatson if (M_TRAILINGSPACE(mb) == 0) { 714223073Sae MGET(mb2, M_WAIT, MT_DATA); 715223073Sae if (siz >= MINCLSIZE) 716223073Sae MCLGET(mb2, M_WAIT); 717223073Sae mb->m_next = mb2; 718223073Sae mb = mb2; 719223073Sae mb->m_len = 0; 720223073Sae bpos = mtod(mb, caddr_t); 721223073Sae } 722223073Sae i = min(siz, M_TRAILINGSPACE(mb)); 723223073Sae bcopy(auth_str, bpos, i); 724223073Sae mb->m_len += i; 725223073Sae auth_str += i; 726223073Sae bpos += i; 727223073Sae siz -= i; 728223073Sae } 729223073Sae if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 730223073Sae for (i = 0; i < siz; i++) 731223073Sae *bpos++ = '\0'; 732223073Sae mb->m_len += siz; 733223073Sae } 734223073Sae break; 735223073Sae }; 736223073Sae 737223073Sae /* 738223073Sae * And the verifier... 739223073Sae */ 740223073Sae nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 741223073Sae if (verf_str) { 742223073Sae *tl++ = txdr_unsigned(RPCAUTH_KERB4); 743223073Sae *tl = txdr_unsigned(verf_len); 744130363Scsjp siz = verf_len; 745222488Srwatson while (siz > 0) { 746196201Sjulian if (M_TRAILINGSPACE(mb) == 0) { 747183606Sbz MGET(mb2, M_WAIT, MT_DATA); 748222488Srwatson if (siz >= MINCLSIZE) 749122265Ssam MCLGET(mb2, M_WAIT); 750183398Srwatson mb->m_next = mb2; 751130363Scsjp mb = mb2; 752200601Sluigi mb->m_len = 0; 753200601Sluigi bpos = mtod(mb, caddr_t); 754130363Scsjp } 755183398Srwatson i = min(siz, M_TRAILINGSPACE(mb)); 756130363Scsjp bcopy(verf_str, bpos, i); 757130363Scsjp mb->m_len += i; 758223073Sae verf_str += i; 759130363Scsjp bpos += i; 760194498Sbrooks siz -= i; 761194498Sbrooks } 762194498Sbrooks if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 763194498Sbrooks for (i = 0; i < siz; i++) 764194498Sbrooks *bpos++ = '\0'; 765223073Sae mb->m_len += siz; 766204591Sluigi } 767122265Ssam } else { 768122265Ssam *tl++ = txdr_unsigned(RPCAUTH_NULL); 76998943Sluigi *tl = 0; 770201527Sluigi } 771201527Sluigi mb->m_next = mrest; 772201527Sluigi mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 773200838Sluigi mreq->m_pkthdr.rcvif = (struct ifnet *)0; 774200838Sluigi *mbp = mb; 775200855Sluigi return (mreq); 776200855Sluigi} 777200838Sluigi 778201527Sluigi/* 779201527Sluigi * copies mbuf chain to the uio scatter/gather list 780201527Sluigi */ 781201527Sluigiint 782200838Sluiginfsm_mbuftouio(mrep, uiop, siz, dpos) 783200838Sluigi struct mbuf **mrep; 784200838Sluigi register struct uio *uiop; 78598943Sluigi int siz; 78698943Sluigi caddr_t *dpos; 78798943Sluigi{ 78898943Sluigi register char *mbufcp, *uiocp; 78998943Sluigi register int xfer, left, len; 79098943Sluigi register struct mbuf *mp; 79198943Sluigi long uiosiz, rem; 79298943Sluigi int error = 0; 79398943Sluigi 794200601Sluigi mp = *mrep; 795165738Sjulian mbufcp = *dpos; 796165738Sjulian len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 797200601Sluigi rem = nfsm_rndup(siz)-siz; 79898943Sluigi while (siz > 0) { 79998943Sluigi if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 80098943Sluigi return (EFBIG); 80198943Sluigi left = uiop->uio_iov->iov_len; 80298943Sluigi uiocp = uiop->uio_iov->iov_base; 80398943Sluigi if (left > siz) 80498943Sluigi left = siz; 805225044Sbz uiosiz = left; 80698943Sluigi while (left > 0) { 807201527Sluigi while (len == 0) { 80898943Sluigi mp = mp->m_next; 80998943Sluigi if (mp == NULL) 81098943Sluigi return (EBADRPC); 811140224Sglebius mbufcp = mtod(mp, caddr_t); 812140224Sglebius len = mp->m_len; 813140224Sglebius } 814140224Sglebius xfer = (left > len) ? len : left; 815140224Sglebius#ifdef notdef 816140224Sglebius /* Not Yet.. */ 817201527Sluigi if (uiop->uio_iov->iov_op != NULL) 818201527Sluigi (*(uiop->uio_iov->iov_op)) 81998943Sluigi (mbufcp, uiocp, xfer); 82098943Sluigi else 821133920Sandre#endif 82298943Sluigi if (uiop->uio_segflg == UIO_SYSSPACE) 82398943Sluigi bcopy(mbufcp, uiocp, xfer); 824183550Szec else 82598943Sluigi copyout(mbufcp, uiocp, xfer); 826200601Sluigi left -= xfer; 82798943Sluigi len -= xfer; 82898943Sluigi mbufcp += xfer; 82998943Sluigi uiocp += xfer; 83098943Sluigi uiop->uio_offset += xfer; 83198943Sluigi uiop->uio_resid -= xfer; 83298943Sluigi } 833101978Sluigi if (uiop->uio_iov->iov_len <= siz) { 83498943Sluigi uiop->uio_iovcnt--; 83598943Sluigi uiop->uio_iov++; 836165738Sjulian } else { 837165738Sjulian uiop->uio_iov->iov_base += uiosiz; 83898943Sluigi uiop->uio_iov->iov_len -= uiosiz; 83998943Sluigi } 84098943Sluigi siz -= uiosiz; 84198943Sluigi } 84298943Sluigi *dpos = mbufcp; 84398943Sluigi *mrep = mp; 844165738Sjulian if (rem > 0) { 845165738Sjulian if (len < rem) 846165738Sjulian error = nfs_adv(mrep, dpos, rem, len); 847165738Sjulian else 84898943Sluigi *dpos += rem; 84998943Sluigi } 85098943Sluigi return (error); 85198943Sluigi} 85298943Sluigi 853130363Scsjp/* 854130363Scsjp * copies a uio scatter/gather list to an mbuf chain. 855130363Scsjp * NOTE: can ony handle iovcnt == 1 856130363Scsjp */ 857130363Scsjpint 858130363Scsjpnfsm_uiotombuf(uiop, mq, siz, bpos) 859204591Sluigi register struct uio *uiop; 860204591Sluigi struct mbuf **mq; 861204591Sluigi int siz; 862194498Sbrooks caddr_t *bpos; 863204591Sluigi{ 864194498Sbrooks register char *uiocp; 865130363Scsjp register struct mbuf *mp, *mp2; 866130363Scsjp register int xfer, left, mlen; 86798943Sluigi int uiosiz, clflg, rem; 868150636Smlaier char *cp; 86998943Sluigi 87098943Sluigi#ifdef DIAGNOSTIC 87198943Sluigi if (uiop->uio_iovcnt != 1) 87298943Sluigi panic("nfsm_uiotombuf: iovcnt != 1"); 87398943Sluigi#endif 874200855Sluigi 87598943Sluigi if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 87698943Sluigi clflg = 1; 87798943Sluigi else 878147758Smlaier clflg = 0; 87998943Sluigi rem = nfsm_rndup(siz)-siz; 88098943Sluigi mp = mp2 = *mq; 88198943Sluigi while (siz > 0) { 88298943Sluigi left = uiop->uio_iov->iov_len; 88398943Sluigi uiocp = uiop->uio_iov->iov_base; 88498943Sluigi if (left > siz) 88598943Sluigi left = siz; 88698943Sluigi uiosiz = left; 887225032Sbz while (left > 0) { 888225032Sbz mlen = M_TRAILINGSPACE(mp); 889225032Sbz if (mlen == 0) { 890225032Sbz MGET(mp, M_WAIT, MT_DATA); 891225030Sbz if (clflg) 89298943Sluigi MCLGET(mp, M_WAIT); 89398943Sluigi mp->m_len = 0; 894225032Sbz mp2->m_next = mp; 89598943Sluigi mp2 = mp; 89698943Sluigi mlen = M_TRAILINGSPACE(mp); 89798943Sluigi } 89898943Sluigi xfer = (left > mlen) ? mlen : left; 89998943Sluigi#ifdef notdef 90098943Sluigi /* Not Yet.. */ 90198943Sluigi if (uiop->uio_iov->iov_op != NULL) 90298943Sluigi (*(uiop->uio_iov->iov_op)) 90398943Sluigi (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 90498943Sluigi else 90598943Sluigi#endif 90698943Sluigi if (uiop->uio_segflg == UIO_SYSSPACE) 90798943Sluigi bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 90898943Sluigi else 90998943Sluigi copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 910201122Sluigi mp->m_len += xfer; 911201122Sluigi left -= xfer; 91298943Sluigi uiocp += xfer; 913201122Sluigi uiop->uio_offset += xfer; 914115750Skbyanc uiop->uio_resid -= xfer; 915201122Sluigi } 916145093Sbrooks uiop->uio_iov->iov_base += uiosiz; 917145093Sbrooks uiop->uio_iov->iov_len -= uiosiz; 918145093Sbrooks siz -= uiosiz; 919145093Sbrooks } 920145093Sbrooks if (rem > 0) { 921145093Sbrooks if (rem > M_TRAILINGSPACE(mp)) { 92298943Sluigi MGET(mp, M_WAIT, MT_DATA); 92398943Sluigi mp->m_len = 0; 924181803Sbz mp2->m_next = mp; 92598943Sluigi } 92698943Sluigi cp = mtod(mp, caddr_t)+mp->m_len; 927145093Sbrooks for (left = 0; left < rem; left++) 928145093Sbrooks *cp++ = '\0'; 929145093Sbrooks mp->m_len += rem; 930145093Sbrooks *bpos = cp; 93198943Sluigi } else 932145093Sbrooks *bpos = mtod(mp, caddr_t)+mp->m_len; 933205173Sluigi *mq = mp; 934145246Sbrooks return (0); 935145246Sbrooks} 936205173Sluigi 937205173Sluigi/* 938145246Sbrooks * Help break down an mbuf chain by setting the first siz bytes contiguous 939205173Sluigi * pointed to by returned val. 940146894Smlaier * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 94198943Sluigi * cases. (The macros use the vars. dpos and dpos2) 942200059Sluigi */ 943200059Sluigiint 944196423Sjuliannfsm_disct(mdp, dposp, siz, left, cp2) 945145093Sbrooks struct mbuf **mdp; 946145093Sbrooks caddr_t *dposp; 947187822Sluigi int siz; 948200040Sluigi int left; 949115750Skbyanc caddr_t *cp2; 950178888Sjulian{ 951145093Sbrooks register struct mbuf *mp, *mp2; 952149020Sbz register int siz2, xfer; 95398943Sluigi register caddr_t p; 954145093Sbrooks 955145093Sbrooks mp = *mdp; 956145093Sbrooks while (left == 0) { 957145093Sbrooks *mdp = mp = mp->m_next; 958145093Sbrooks if (mp == NULL) 959145093Sbrooks return (EBADRPC); 960220796Sglebius left = mp->m_len; 961220796Sglebius *dposp = mtod(mp, caddr_t); 962200601Sluigi } 963220796Sglebius if (left >= siz) { 964200601Sluigi *cp2 = *dposp; 965200601Sluigi *dposp += siz; 966200601Sluigi } else if (mp->m_next == NULL) { 967200601Sluigi return (EBADRPC); 968200601Sluigi } else if (siz > MHLEN) { 969200601Sluigi panic("nfs S too big"); 970145093Sbrooks } else { 97198943Sluigi MGET(mp2, M_WAIT, MT_DATA); 972165738Sjulian mp2->m_next = mp->m_next; 973165738Sjulian mp->m_next = mp2; 974165738Sjulian mp->m_len -= left; 975165738Sjulian mp = mp2; 976165738Sjulian *cp2 = p = mtod(mp, caddr_t); 977165738Sjulian bcopy(*dposp, p, left); /* Copy what was left */ 978145246Sbrooks siz2 = siz-left; 979145246Sbrooks p += left; 980165738Sjulian mp2 = mp->m_next; 981165738Sjulian /* Loop around copying up the siz2 bytes */ 982145246Sbrooks while (siz2 > 0) { 983145246Sbrooks if (mp2 == NULL) 984145246Sbrooks return (EBADRPC); 985165738Sjulian xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 986145246Sbrooks if (xfer > 0) { 987145246Sbrooks bcopy(mtod(mp2, caddr_t), p, xfer); 988225033Sbz NFSMADV(mp2, xfer); 989145246Sbrooks mp2->m_len -= xfer; 990145246Sbrooks p += xfer; 991145246Sbrooks siz2 -= xfer; 992205173Sluigi } 993145246Sbrooks if (siz2 > 0) 994145246Sbrooks mp2 = mp2->m_next; 995145246Sbrooks } 996145246Sbrooks mp->m_len = siz; 997145246Sbrooks *mdp = mp2; 998145246Sbrooks *dposp = mtod(mp2, caddr_t); 999205173Sluigi } 1000205173Sluigi return (0); 1001145246Sbrooks} 1002145246Sbrooks 1003164258Sbz/* 1004164258Sbz * Advance the position in the mbuf chain. 1005164258Sbz */ 1006164258Sbzint 1007164258Sbznfs_adv(mdp, dposp, offs, left) 1008164258Sbz struct mbuf **mdp; 1009145246Sbrooks caddr_t *dposp; 1010145246Sbrooks int offs; 1011145246Sbrooks int left; 1012145246Sbrooks{ 1013145246Sbrooks register struct mbuf *m; 1014145246Sbrooks register int s; 1015149020Sbz 1016145246Sbrooks m = *mdp; 1017145246Sbrooks s = left; 1018149020Sbz while (s < offs) { 1019145246Sbrooks offs -= s; 1020145246Sbrooks m = m->m_next; 1021145246Sbrooks if (m == NULL) 1022145246Sbrooks return (EBADRPC); 1023149020Sbz s = m->m_len; 1024145246Sbrooks } 1025159857Sume *mdp = m; 1026159857Sume *dposp = mtod(m, caddr_t)+offs; 1027169245Sbz return (0); 1028159857Sume} 1029169245Sbz 1030169245Sbz/* 1031169245Sbz * Copy a string into mbufs for the hard cases... 1032159857Sume */ 1033225036Sbzint 1034225036Sbznfsm_strtmbuf(mb, bpos, cp, siz) 1035225036Sbz struct mbuf **mb; 1036225036Sbz char **bpos; 1037225036Sbz const char *cp; 1038181803Sbz long siz; 1039149020Sbz{ 1040149020Sbz register struct mbuf *m1 = NULL, *m2; 1041149020Sbz long left, xfer, len, tlen; 1042145246Sbrooks u_int32_t *tl; 1043149020Sbz int putsize; 1044145246Sbrooks 1045145246Sbrooks putsize = 1; 1046145246Sbrooks m2 = *mb; 1047145246Sbrooks left = M_TRAILINGSPACE(m2); 1048149020Sbz if (left > 0) { 1049145246Sbrooks tl = ((u_int32_t *)(*bpos)); 1050145246Sbrooks *tl++ = txdr_unsigned(siz); 1051145246Sbrooks putsize = 0; 1052145246Sbrooks left -= NFSX_UNSIGNED; 1053149020Sbz m2->m_len += NFSX_UNSIGNED; 1054149020Sbz if (left > 0) { 1055225032Sbz bcopy(cp, (caddr_t) tl, left); 1056149020Sbz siz -= left; 1057225030Sbz cp += left; 1058225032Sbz m2->m_len += left; 1059225036Sbz left = 0; 1060225036Sbz } 1061225036Sbz } 1062181803Sbz /* Loop around adding mbufs */ 1063149020Sbz while (siz > 0) { 1064149020Sbz MGET(m1, M_WAIT, MT_DATA); 1065149020Sbz if (siz > MLEN) 1066205173Sluigi MCLGET(m1, M_WAIT); 1067149020Sbz m1->m_len = NFSMSIZ(m1); 1068149020Sbz m2->m_next = m1; 1069145246Sbrooks m2 = m1; 1070145246Sbrooks tl = mtod(m1, u_int32_t *); 1071149020Sbz tlen = 0; 1072149020Sbz if (putsize) { 1073149020Sbz *tl++ = txdr_unsigned(siz); 1074149020Sbz m1->m_len -= NFSX_UNSIGNED; 1075149020Sbz tlen = NFSX_UNSIGNED; 1076149020Sbz putsize = 0; 1077149020Sbz } 1078149020Sbz if (siz < m1->m_len) { 1079149020Sbz len = nfsm_rndup(siz); 1080145246Sbrooks xfer = siz; 1081145246Sbrooks if (xfer < len) 1082149020Sbz *(tl+(xfer>>2)) = 0; 1083145246Sbrooks } else { 1084145246Sbrooks xfer = len = m1->m_len; 1085145246Sbrooks } 1086145246Sbrooks bcopy(cp, (caddr_t) tl, xfer); 1087149020Sbz m1->m_len = len+tlen; 1088149020Sbz siz -= xfer; 1089149020Sbz cp += xfer; 1090149020Sbz } 1091149020Sbz *mb = m1; 1092149020Sbz *bpos = mtod(m1, caddr_t)+m1->m_len; 1093149020Sbz return (0); 1094149020Sbz} 1095174479Sdwmalone 1096174479Sdwmalone/* 1097174479Sdwmalone * Called once to initialize data structures... 1098174479Sdwmalone */ 1099174479Sdwmaloneint 1100174479Sdwmalonenfs_init(vfsp) 1101149020Sbz struct vfsconf *vfsp; 1102149020Sbz{ 1103146704Stanimura register int i; 1104146704Stanimura 1105146704Stanimura nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 1106146704Stanimura 1107146704Stanimura nfs_mount_type = vfsp->vfc_typenum; 1108161767Sjhay nfsrtt.pos = 0; 1109161767Sjhay rpc_vers = txdr_unsigned(RPC_VER2); 1110161767Sjhay rpc_call = txdr_unsigned(RPC_CALL); 1111161767Sjhay rpc_reply = txdr_unsigned(RPC_REPLY); 1112161767Sjhay rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 1113163069Sbz rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 1114163069Sbz rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 1115163069Sbz rpc_autherr = txdr_unsigned(RPC_AUTHERR); 1116163069Sbz rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1117163069Sbz rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 1118163069Sbz nfs_prog = txdr_unsigned(NFS_PROG); 1119163069Sbz nqnfs_prog = txdr_unsigned(NQNFS_PROG); 1120163069Sbz nfs_true = txdr_unsigned(TRUE); 1121163069Sbz nfs_false = txdr_unsigned(FALSE); 1122163069Sbz nfs_xdrneg1 = txdr_unsigned(-1); 1123159857Sume nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1124159857Sume if (nfs_ticks < 1) 1125159857Sume nfs_ticks = 1; 1126159857Sume /* Ensure async daemons disabled */ 1127159857Sume for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 1128159857Sume nfs_iodwant[i] = (struct proc *)0; 1129159857Sume nfs_iodmount[i] = (struct nfsmount *)0; 1130159857Sume } 1131145246Sbrooks nfs_nhinit(); /* Init the nfsnode table */ 1132225036Sbz#ifndef NFS_NOSERVER 1133225036Sbz nfsrv_init(0); /* Init server data structures */ 1134225036Sbz nfsrv_initcache(); /* Init the server request cache */ 1135225036Sbz#endif 1136181803Sbz 1137149020Sbz /* 1138159857Sume * Initialize the nqnfs server stuff. 1139145246Sbrooks */ 1140145246Sbrooks if (nqnfsstarttime == 0) { 1141145246Sbrooks nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 1142165738Sjulian + nqsrv_clockskew + nqsrv_writeslack; 1143165738Sjulian NQLOADNOVRAM(nqnfsstarttime); 1144165738Sjulian CIRCLEQ_INIT(&nqtimerhead); 1145165738Sjulian nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 1146145246Sbrooks } 1147145246Sbrooks 1148165738Sjulian /* 1149145246Sbrooks * Initialize reply list and start timer 1150165738Sjulian */ 1151146894Smlaier TAILQ_INIT(&nfs_reqq); 1152145093Sbrooks 1153145093Sbrooks nfs_timer(0); 115498943Sluigi 1155145093Sbrooks /* 1156145093Sbrooks * Set up lease_check and lease_updatetime so that other parts 1157145093Sbrooks * of the system can call us, if we are loadable. 1158145093Sbrooks */ 1159145093Sbrooks#ifndef NFS_NOSERVER 1160145093Sbrooks nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; 1161201527Sluigi default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; 1162201527Sluigi#endif 1163201122Sluigi nfs_prev_lease_updatetime = lease_updatetime; 116498943Sluigi lease_updatetime = nfs_lease_updatetime; 1165145093Sbrooks nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 1166145093Sbrooks sysent[SYS_nfssvc].sy_narg = 2; 1167145093Sbrooks nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 1168145093Sbrooks sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 1169145093Sbrooks 1170145093Sbrooks nfs_pbuf_freecnt = nswbuf / 2 + 1; 1171205173Sluigi 1172205173Sluigi return (0); 1173145093Sbrooks} 117498943Sluigi 1175220211Saeint 1176220211Saenfs_uninit(vfsp) 1177220211Sae struct vfsconf *vfsp; 1178220211Sae{ 1179220211Sae 1180220211Sae untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 1181145093Sbrooks nfs_mount_type = -1; 1182145093Sbrooks#ifndef NFS_NOSERVER 1183145093Sbrooks default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; 1184145093Sbrooks#endif 1185145093Sbrooks lease_updatetime = nfs_prev_lease_updatetime; 118698943Sluigi sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 1187145093Sbrooks sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 1188145565Sbrooks return (0); 1189205173Sluigi} 1190145093Sbrooks 119198943Sluigi/* 1192145093Sbrooks * Attribute cache routines. 1193145093Sbrooks * nfs_loadattrcache() - loads or updates the cache contents from attributes 119498943Sluigi * that are on the mbuf list 1195145093Sbrooks * nfs_getattrcache() - returns valid attributes if found in cache, returns 119698943Sluigi * error otherwise 1197165738Sjulian */ 1198145093Sbrooks 1199145093Sbrooks/* 1200145093Sbrooks * Load the attribute cache (that lives in the nfsnode entry) with 120198943Sluigi * the values on the mbuf list and 1202145093Sbrooks * Iff vap not NULL 1203145093Sbrooks * copy the attributes to *vaper 1204145093Sbrooks */ 1205145093Sbrooksint 120698943Sluiginfs_loadattrcache(vpp, mdp, dposp, vaper) 120798943Sluigi struct vnode **vpp; 1208138642Scsjp struct mbuf **mdp; 1209197952Sjulian caddr_t *dposp; 1210197952Sjulian struct vattr *vaper; 1211197952Sjulian{ 1212197952Sjulian register struct vnode *vp = *vpp; 1213201527Sluigi register struct vattr *vap; 121498943Sluigi register struct nfs_fattr *fp; 1215200629Sluigi register struct nfsnode *np; 1216200629Sluigi register int32_t t1; 1217201527Sluigi caddr_t cp2; 1218200855Sluigi int error = 0, rdev; 1219200855Sluigi struct mbuf *md; 122098943Sluigi enum vtype vtyp; 1221201527Sluigi u_short vmode; 1222201527Sluigi struct timespec mtime; 1223201527Sluigi int v3 = NFS_ISV3(vp); 1224201527Sluigi 122598943Sluigi md = *mdp; 1226200855Sluigi t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 122798943Sluigi if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) 122898943Sluigi return (error); 122998943Sluigi fp = (struct nfs_fattr *)cp2; 123098943Sluigi if (v3) { 1231200059Sluigi vtyp = nfsv3tov_type(fp->fa_type); 1232200059Sluigi vmode = fxdr_unsigned(u_short, fp->fa_mode); 1233200059Sluigi rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 1234200059Sluigi fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 1235200855Sluigi fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1236200059Sluigi } else { 1237200059Sluigi vtyp = nfsv2tov_type(fp->fa_type); 1238200059Sluigi vmode = fxdr_unsigned(u_short, fp->fa_mode); 1239200059Sluigi /* 1240200059Sluigi * XXX 1241200059Sluigi * 1242200059Sluigi * The duplicate information returned in fa_type and fa_mode 1243200059Sluigi * is an ambiguity in the NFS version 2 protocol. 1244200855Sluigi * 1245200059Sluigi * VREG should be taken literally as a regular file. If a 124698943Sluigi * server intents to return some type information differently 1247200855Sluigi * in the upper bits of the mode field (e.g. for sockets, or 124898943Sluigi * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 1249153374Sglebius * leave the examination of the mode bits even in the VREG 1250153374Sglebius * case to avoid breakage for bogus servers, but we make sure 1251200855Sluigi * that there are actually type bits set in the upper part of 125298943Sluigi * fa_mode (and failing that, trust the va_type field). 1253200855Sluigi * 1254181803Sbz * NFSv3 cleared the issue, and requires fa_mode to not 1255101628Sluigi * contain any type information (while also introduing sockets 1256101628Sluigi * and FIFOs for fa_type). 125798943Sluigi */ 125898943Sluigi if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 125998943Sluigi vtyp = IFTOVT(vmode); 126099622Sluigi rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 126198943Sluigi fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 126298943Sluigi 126398943Sluigi /* 126498943Sluigi * Really ugly NFSv2 kludge. 126598943Sluigi */ 126698943Sluigi if (vtyp == VCHR && rdev == 0xffffffff) 126798943Sluigi vtyp = VFIFO; 1268200059Sluigi } 126998943Sluigi 127098943Sluigi /* 127198943Sluigi * If v_type == VNON it is a new node, so fill in the v_type, 127298943Sluigi * n_mtime fields. Check to see if it represents a special 127398943Sluigi * device, and if so, check for a possible alias. Once the 127498943Sluigi * correct vnode has been obtained, fill in the rest of the 127598943Sluigi * information. 127698943Sluigi */ 127798943Sluigi np = VTONFS(vp); 127898943Sluigi if (vp->v_type != vtyp) { 127998943Sluigi vp->v_type = vtyp; 128098943Sluigi if (vp->v_type == VFIFO) { 128198943Sluigi vp->v_op = fifo_nfsv2nodeop_p; 128299622Sluigi } 128399622Sluigi if (vp->v_type == VCHR || vp->v_type == VBLK) { 128498943Sluigi vp->v_op = spec_nfsv2nodeop_p; 128599622Sluigi addaliasu(vp, rdev); 128699622Sluigi } 128799622Sluigi np->n_mtime = mtime.tv_sec; 128899622Sluigi } 128999622Sluigi vap = &np->n_vattr; 129099622Sluigi vap->va_type = vtyp; 129199622Sluigi vap->va_mode = (vmode & 07777); 129298943Sluigi vap->va_rdev = rdev; 129399622Sluigi vap->va_mtime = mtime; 129499622Sluigi vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 129598943Sluigi if (v3) { 129698943Sluigi vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 129798943Sluigi vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 129898943Sluigi vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 129999622Sluigi vap->va_size = fxdr_hyper(&fp->fa3_size); 130098943Sluigi vap->va_blocksize = NFS_FABLKSIZE; 130198943Sluigi vap->va_bytes = fxdr_hyper(&fp->fa3_used); 130298943Sluigi vap->va_fileid = fxdr_unsigned(int32_t, 1303133600Scsjp fp->fa3_fileid.nfsuquad[1]); 130498943Sluigi fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 130598943Sluigi fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1306145246Sbrooks vap->va_flags = 0; 130798943Sluigi vap->va_filerev = 0; 130898943Sluigi } else { 1309223073Sae vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 131099622Sluigi vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1311122265Ssam vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1312122265Ssam vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1313122265Ssam vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 1314122265Ssam vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 1315223073Sae * NFS_FABLKSIZE; 1316204591Sluigi vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1317223073Sae fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1318204591Sluigi vap->va_flags = 0; 1319223073Sae vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 1320204591Sluigi fp->fa2_ctime.nfsv2_sec); 132199622Sluigi vap->va_ctime.tv_nsec = 0; 132298943Sluigi vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 132398943Sluigi vap->va_filerev = 0; 132499622Sluigi } 1325234597Smelifaro if (vap->va_size != np->n_size) { 132699622Sluigi if (vap->va_type == VREG) { 132798943Sluigi if (np->n_flag & NMODIFIED) { 132898943Sluigi if (vap->va_size < np->n_size) 1329234597Smelifaro vap->va_size = np->n_size; 1330234597Smelifaro else 133199622Sluigi np->n_size = vap->va_size; 133298943Sluigi } else { 133398943Sluigi np->n_size = vap->va_size; 133499622Sluigi } 1335234597Smelifaro vnode_pager_setsize(vp, np->n_size); 1336234597Smelifaro } else { 133799622Sluigi np->n_size = vap->va_size; 133898943Sluigi } 133998943Sluigi } 134098943Sluigi np->n_attrstamp = time_second; 134198943Sluigi if (vaper != NULL) { 134298943Sluigi bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 134398943Sluigi if (np->n_flag & NCHG) { 134498943Sluigi if (np->n_flag & NACC) 134598943Sluigi vaper->va_atime = np->n_atim; 134698943Sluigi if (np->n_flag & NUPD) 134799622Sluigi vaper->va_mtime = np->n_mtim; 134899622Sluigi } 134999622Sluigi } 135099622Sluigi return (0); 135198943Sluigi} 135299622Sluigi 135398943Sluigi#ifdef NFS_ACDEBUG 135498943Sluigi#include <sys/sysctl.h> 135598943SluigiSYSCTL_DECL(_vfs_nfs); 135698943Sluigistatic int nfs_acdebug; 135798943SluigiSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 135898943Sluigi#endif 135998943Sluigi 136099622Sluigi/* 136199622Sluigi * Check the time stamp 1362165738Sjulian * If the cache is valid, copy contents to *vap and return 0 1363165738Sjulian * otherwise return an error 136498943Sluigi */ 136599622Sluigiint 136698943Sluiginfs_getattrcache(vp, vaper) 136798943Sluigi register struct vnode *vp; 1368145246Sbrooks struct vattr *vaper; 136999622Sluigi{ 137098943Sluigi register struct nfsnode *np; 137198943Sluigi register struct vattr *vap; 137299622Sluigi struct nfsmount *nmp; 137399622Sluigi int timeo; 137498943Sluigi 137598943Sluigi np = VTONFS(vp); 137699622Sluigi vap = &np->n_vattr; 137799622Sluigi nmp = VFSTONFS(vp->v_mount); 137898943Sluigi /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 1379136073Sgreen timeo = (time_second - np->n_mtime) / 10; 1380201527Sluigi 1381201527Sluigi#ifdef NFS_ACDEBUG 1382201527Sluigi if (nfs_acdebug>1) 1383201527Sluigi printf("nfs_getattrcache: initial timeo = %d\n", timeo); 1384210120Sluigi#endif 1385201527Sluigi 1386201527Sluigi if (vap->va_type == VDIR) { 1387201527Sluigi if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 1388201527Sluigi timeo = nmp->nm_acdirmin; 1389136073Sgreen else if (timeo > nmp->nm_acdirmax) 1390136073Sgreen timeo = nmp->nm_acdirmax; 139198943Sluigi } else { 139298943Sluigi if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 139398943Sluigi timeo = nmp->nm_acregmin; 139498943Sluigi else if (timeo > nmp->nm_acregmax) 139598943Sluigi timeo = nmp->nm_acregmax; 139699622Sluigi } 139799622Sluigi 139898943Sluigi#ifdef NFS_ACDEBUG 139998943Sluigi if (nfs_acdebug > 2) 1400147758Smlaier printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 1401147758Smlaier nmp->nm_acregmin, nmp->nm_acregmax, 140299622Sluigi nmp->nm_acdirmin, nmp->nm_acdirmax); 140399622Sluigi 1404105775Smaxim if (nfs_acdebug) 1405130281Sru printf("nfs_getattrcache: age = %d; final timeo = %d\n", 1406130281Sru (time_second - np->n_attrstamp), timeo); 1407147758Smlaier#endif 1408201122Sluigi 1409130281Sru if ((time_second - np->n_attrstamp) >= timeo) { 1410130281Sru nfsstats.attrcache_misses++; 1411187822Sluigi return (ENOENT); 1412130281Sru } 1413200567Sluigi nfsstats.attrcache_hits++; 1414201122Sluigi if (vap->va_size != np->n_size) { 1415201122Sluigi if (vap->va_type == VREG) { 1416201122Sluigi if (np->n_flag & NMODIFIED) { 1417200567Sluigi if (vap->va_size < np->n_size) 1418200567Sluigi vap->va_size = np->n_size; 1419201122Sluigi else 1420200567Sluigi np->n_size = vap->va_size; 1421201122Sluigi } else { 1422205173Sluigi np->n_size = vap->va_size; 1423205173Sluigi } 1424200567Sluigi vnode_pager_setsize(vp, np->n_size); 1425200567Sluigi } else { 1426200567Sluigi np->n_size = vap->va_size; 1427200567Sluigi } 1428200567Sluigi } 1429200567Sluigi bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 1430201122Sluigi if (np->n_flag & NCHG) { 1431200567Sluigi if (np->n_flag & NACC) 1432201150Sluigi vaper->va_atime = np->n_atim; 1433200567Sluigi if (np->n_flag & NUPD) 1434200567Sluigi vaper->va_mtime = np->n_mtim; 1435200567Sluigi } 1436223073Sae return (0); 1437204591Sluigi} 1438223073Sae 1439200567Sluigi#ifndef NFS_NOSERVER 1440201122Sluigi/* 1441200567Sluigi * Set up nameidata for a lookup() call and do it. 1442201122Sluigi * 1443204591Sluigi * If pubflag is set, this call is done for a lookup operation on the 1444223073Sae * public filehandle. In that case we allow crossing mountpoints and 1445204591Sluigi * absolute pathnames. However, the caller is expected to check that 1446204591Sluigi * the lookup result is within the public fs, and deny access if 1447204591Sluigi * it is not. 1448204591Sluigi * 1449204591Sluigi * nfs_namei() clears out garbage fields that namei() might leave garbage. 1450201122Sluigi * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 1451200567Sluigi * error occurs but the parent was not requested. 1452200567Sluigi * 1453200567Sluigi * dirp may be set whether an error is returned or not, and must be 1454201122Sluigi * released by the caller. 1455201122Sluigi */ 1456130281Sruint 1457130281Srunfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 1458130281Sru register struct nameidata *ndp; 1459130281Sru fhandle_t *fhp; 1460130281Sru int len; 1461153374Sglebius struct nfssvc_sock *slp; 1462153374Sglebius struct sockaddr *nam; 1463234597Smelifaro struct mbuf **mdp; 1464234597Smelifaro caddr_t *dposp; 1465234597Smelifaro struct vnode **retdirp; 1466234597Smelifaro struct proc *p; 1467234597Smelifaro int kerbflag, pubflag; 1468234597Smelifaro{ 1469234597Smelifaro register int i, rem; 1470234597Smelifaro register struct mbuf *md; 1471234597Smelifaro register char *fromcp, *tocp, *cp; 1472234597Smelifaro struct iovec aiov; 1473234597Smelifaro struct uio auio; 1474130281Sru struct vnode *dp; 1475130281Sru int error, rdonly, linklen; 1476130281Sru struct componentname *cnp = &ndp->ni_cnd; 147798943Sluigi 1478117327Sluigi *retdirp = (struct vnode *)0; 1479147758Smlaier cnp->cn_pnbuf = zalloc(namei_zone); 1480117327Sluigi 1481117327Sluigi /* 1482117327Sluigi * Copy the name from the mbuf list to ndp->ni_pnbuf 1483117327Sluigi * and set the various ndp fields appropriately. 1484117327Sluigi */ 1485117327Sluigi fromcp = *dposp; 1486117327Sluigi tocp = cnp->cn_pnbuf; 1487117327Sluigi md = *mdp; 1488117327Sluigi rem = mtod(md, caddr_t) + md->m_len - fromcp; 148999622Sluigi for (i = 0; i < len; i++) { 149098943Sluigi while (rem == 0) { 149198943Sluigi md = md->m_next; 1492147758Smlaier if (md == NULL) { 149399622Sluigi error = EBADRPC; 149498943Sluigi goto out; 149599622Sluigi } 149699622Sluigi fromcp = mtod(md, caddr_t); 1497202459Sume rem = md->m_len; 149899622Sluigi } 1499204591Sluigi if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 1500202459Sume error = EACCES; 1501202459Sume goto out; 1502204591Sluigi } 1503202459Sume *tocp++ = *fromcp++; 150499622Sluigi rem--; 1505105775Smaxim } 150698943Sluigi *tocp = '\0'; 150798943Sluigi *mdp = md; 1508147758Smlaier *dposp = fromcp; 150999622Sluigi len = nfsm_rndup(len)-len; 151099622Sluigi if (len > 0) { 151199622Sluigi if (rem >= len) 1512105886Sluigi *dposp += len; 1513105886Sluigi else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 151498943Sluigi goto out; 151599622Sluigi } 151699622Sluigi 151799622Sluigi /* 151899622Sluigi * Extract and set starting directory. 151999622Sluigi */ 152099622Sluigi error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 152199622Sluigi nam, &rdonly, kerbflag, pubflag); 152299622Sluigi if (error) 152398943Sluigi goto out; 152498943Sluigi if (dp->v_type != VDIR) { 1525147758Smlaier vrele(dp); 1526147758Smlaier error = ENOTDIR; 152799622Sluigi goto out; 152899622Sluigi } 152998943Sluigi 153098943Sluigi if (rdonly) 1531147758Smlaier cnp->cn_flags |= RDONLY; 153299622Sluigi 153399622Sluigi /* 153499622Sluigi * Set return directory. Reference to dp is implicitly transfered 153599622Sluigi * to the returned pointer 1536202459Sume */ 153799622Sluigi *retdirp = dp; 1538204591Sluigi 1539202459Sume if (pubflag) { 1540202459Sume /* 1541204591Sluigi * Oh joy. For WebNFS, handle those pesky '%' escapes, 1542202459Sume * and the 'native path' indicator. 154399622Sluigi */ 1544105775Smaxim cp = zalloc(namei_zone); 1545204591Sluigi fromcp = cnp->cn_pnbuf; 154698943Sluigi tocp = cp; 154798943Sluigi if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 154898943Sluigi switch ((unsigned char)*fromcp) { 154998943Sluigi case WEBNFS_NATIVE_CHAR: 1550145246Sbrooks /* 155198943Sluigi * 'Native' path for us is the same 155298943Sluigi * as a path according to the NFS spec, 155399622Sluigi * just skip the escape char. 155499622Sluigi */ 155599622Sluigi fromcp++; 155698943Sluigi break; 155799622Sluigi /* 155898943Sluigi * More may be added in the future, range 0x80-0xff 155998943Sluigi */ 156098943Sluigi default: 156198943Sluigi error = EIO; 156299622Sluigi zfree(namei_zone, cp); 156399622Sluigi goto out; 156499622Sluigi } 156598943Sluigi } 156699622Sluigi /* 156798943Sluigi * Translate the '%' escapes, URL-style. 156898943Sluigi */ 156999622Sluigi while (*fromcp != '\0') { 1570145093Sbrooks if (*fromcp == WEBNFS_ESC_CHAR) { 157199622Sluigi if (fromcp[1] != '\0' && fromcp[2] != '\0') { 157298943Sluigi fromcp++; 1573145266Sphk *tocp++ = HEXSTRTOI(fromcp); 1574145246Sbrooks fromcp += 2; 1575145246Sbrooks continue; 1576145246Sbrooks } else { 1577145246Sbrooks error = ENOENT; 1578145246Sbrooks zfree(namei_zone, cp); 1579145246Sbrooks goto out; 1580145246Sbrooks } 1581145266Sphk } else 1582145246Sbrooks *tocp++ = *fromcp++; 158398943Sluigi } 1584147758Smlaier *tocp = '\0'; 1585165738Sjulian zfree(namei_zone, cnp->cn_pnbuf); 158699622Sluigi cnp->cn_pnbuf = cp; 158798943Sluigi } 158898943Sluigi 1589147758Smlaier ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 1590165738Sjulian ndp->ni_segflg = UIO_SYSSPACE; 159199622Sluigi 159298943Sluigi if (pubflag) { 1593116690Sluigi ndp->ni_rootdir = rootvnode; 1594116690Sluigi ndp->ni_loopcnt = 0; 159598943Sluigi if (cnp->cn_pnbuf[0] == '/') 1596147758Smlaier dp = rootvnode; 1597116690Sluigi } else { 1598116690Sluigi cnp->cn_flags |= NOCROSSMOUNT; 1599116690Sluigi } 160098943Sluigi 1601116690Sluigi /* 1602201122Sluigi * Initialize for scan, set ni_startdir and bump ref on dp again 1603116690Sluigi * becuase lookup() will dereference ni_startdir. 1604165738Sjulian */ 1605116690Sluigi 1606165738Sjulian cnp->cn_proc = p; 1607116690Sluigi VREF(dp); 1608116690Sluigi ndp->ni_startdir = dp; 1609116690Sluigi 1610116690Sluigi for (;;) { 1611116690Sluigi cnp->cn_nameptr = cnp->cn_pnbuf; 1612116690Sluigi /* 1613116690Sluigi * Call lookup() to do the real work. If an error occurs, 1614116690Sluigi * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 1615116690Sluigi * we do not have to dereference anything before returning. 1616116690Sluigi * In either case ni_startdir will be dereferenced and NULLed 161799622Sluigi * out. 161898943Sluigi */ 161999475Sluigi error = lookup(ndp); 1620147758Smlaier if (error) 1621165738Sjulian break; 162299622Sluigi 162399475Sluigi /* 162498943Sluigi * Check for encountering a symbolic link. Trivial 1625147758Smlaier * termination occurs if no symlink encountered. 1626165738Sjulian * Note: zfree is safe because error is 0, so we will 162799622Sluigi * not zfree it again when we break. 162898943Sluigi */ 1629136075Sgreen if ((cnp->cn_flags & ISSYMLINK) == 0) { 1630136075Sgreen nfsrv_object_create(ndp->ni_vp); 1631136075Sgreen if (cnp->cn_flags & (SAVENAME | SAVESTART)) 1632136075Sgreen cnp->cn_flags |= HASBUF; 1633136075Sgreen else 1634136075Sgreen zfree(namei_zone, cnp->cn_pnbuf); 1635136075Sgreen break; 1636145093Sbrooks } 1637201122Sluigi 1638136075Sgreen /* 1639136075Sgreen * Validate symlink 1640136075Sgreen */ 1641136075Sgreen if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1642136075Sgreen VOP_UNLOCK(ndp->ni_dvp, 0, p); 1643136075Sgreen if (!pubflag) { 1644136075Sgreen error = EINVAL; 1645136075Sgreen goto badlink2; 1646136075Sgreen } 1647136075Sgreen 1648136075Sgreen if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1649136075Sgreen error = ELOOP; 1650136075Sgreen goto badlink2; 165198943Sluigi } 165299622Sluigi if (ndp->ni_pathlen > 1) 1653145093Sbrooks cp = zalloc(namei_zone); 165499622Sluigi else 165598943Sluigi cp = cnp->cn_pnbuf; 165698943Sluigi aiov.iov_base = cp; 1657220796Sglebius aiov.iov_len = MAXPATHLEN; 165899622Sluigi auio.uio_iov = &aiov; 1659145093Sbrooks auio.uio_iovcnt = 1; 166099622Sluigi auio.uio_offset = 0; 166198943Sluigi auio.uio_rw = UIO_READ; 166298943Sluigi auio.uio_segflg = UIO_SYSSPACE; 166399622Sluigi auio.uio_procp = (struct proc *)0; 166499622Sluigi auio.uio_resid = MAXPATHLEN; 1665145093Sbrooks error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 166699622Sluigi if (error) { 166798943Sluigi badlink1: 166898943Sluigi if (ndp->ni_pathlen > 1) 166999622Sluigi zfree(namei_zone, cp); 167099622Sluigi badlink2: 1671145093Sbrooks vrele(ndp->ni_dvp); 167299622Sluigi vput(ndp->ni_vp); 167398943Sluigi break; 167498943Sluigi } 1675234278Sglebius linklen = MAXPATHLEN - auio.uio_resid; 1676234278Sglebius if (linklen == 0) { 1677234278Sglebius error = ENOENT; 1678234278Sglebius goto badlink1; 1679234278Sglebius } 1680234278Sglebius if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 1681234278Sglebius error = ENAMETOOLONG; 1682234278Sglebius goto badlink1; 1683234278Sglebius } 1684234278Sglebius 1685234278Sglebius /* 1686234278Sglebius * Adjust or replace path 1687234278Sglebius */ 1688234278Sglebius if (ndp->ni_pathlen > 1) { 1689234278Sglebius bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 1690234278Sglebius zfree(namei_zone, cnp->cn_pnbuf); 169199622Sluigi cnp->cn_pnbuf = cp; 169298943Sluigi } else 169398943Sluigi cnp->cn_pnbuf[linklen] = '\0'; 169498943Sluigi ndp->ni_pathlen += linklen; 169599622Sluigi 169699622Sluigi /* 1697145093Sbrooks * Cleanup refs for next loop and check if root directory 169899622Sluigi * should replace current directory. Normally ni_dvp 169999622Sluigi * becomes the new base directory and is cleaned up when 170098943Sluigi * we loop. Explicitly null pointers after invalidation 1701136071Sgreen * to clarify operation. 1702171173Smlaier */ 1703136071Sgreen vput(ndp->ni_vp); 1704136071Sgreen ndp->ni_vp = NULL; 1705136071Sgreen 1706171173Smlaier if (cnp->cn_pnbuf[0] == '/') { 1707171173Smlaier vrele(ndp->ni_dvp); 1708146962Sgreen ndp->ni_dvp = ndp->ni_rootdir; 1709171173Smlaier VREF(ndp->ni_dvp); 1710171173Smlaier } 1711136071Sgreen ndp->ni_startdir = ndp->ni_dvp; 1712136071Sgreen ndp->ni_dvp = NULL; 1713136071Sgreen } 1714136071Sgreen 1715136071Sgreen /* 1716136071Sgreen * nfs_namei() guarentees that fields will not contain garbage 1717136071Sgreen * whether an error occurs or not. This allows the caller to track 1718136071Sgreen * cleanup state trivially. 1719136071Sgreen */ 1720136071Sgreenout: 1721136071Sgreen if (error) { 172298943Sluigi zfree(namei_zone, cnp->cn_pnbuf); 1723200654Sluigi ndp->ni_vp = NULL; 1724225032Sbz ndp->ni_dvp = NULL; 172599622Sluigi ndp->ni_startdir = NULL; 172699622Sluigi cnp->cn_flags &= ~HASBUF; 172798943Sluigi } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 172899475Sluigi ndp->ni_dvp = NULL; 172999622Sluigi } 173099622Sluigi return (error); 173198943Sluigi} 1732112250Scjc 1733112250Scjc/* 1734145246Sbrooks * A fiddled version of m_adj() that ensures null fill to a long 1735116763Sluigi * boundary and only trims off the back end 1736145266Sphk */ 1737145266Sphkvoid 1738145266Sphknfsm_adj(mp, len, nul) 1739147418Smlaier struct mbuf *mp; 1740232292Sbz register int len; 1741145266Sphk int nul; 1742178888Sjulian{ 1743178888Sjulian register struct mbuf *m; 1744112250Scjc register int count, i; 1745112250Scjc register char *cp; 1746128575Sandre 1747128575Sandre /* 1748133485Sandre * Trim from tail. Scan the mbuf chain, 1749147418Smlaier * calculating its length and finding the last mbuf. 1750147418Smlaier * If the adjustment only affects this mbuf, then just 1751147418Smlaier * adjust and return. Otherwise, rescan and truncate 1752232292Sbz * after the remaining size. 1753147418Smlaier */ 1754178888Sjulian count = 0; 1755128575Sandre m = mp; 1756128575Sandre for (;;) { 1757133387Sandre count += m->m_len; 1758133387Sandre if (m->m_next == (struct mbuf *)0) 1759133387Sandre break; 1760147418Smlaier m = m->m_next; 1761147418Smlaier } 1762147418Smlaier if (m->m_len > len) { 1763147418Smlaier m->m_len -= len; 1764147418Smlaier if (nul > 0) { 1765147418Smlaier cp = mtod(m, caddr_t)+m->m_len-nul; 1766147418Smlaier for (i = 0; i < nul; i++) 1767147418Smlaier *cp++ = '\0'; 1768147418Smlaier } 1769147418Smlaier return; 1770232292Sbz } 1771232292Sbz count -= len; 1772147418Smlaier if (count < 0) 1773147418Smlaier count = 0; 1774178888Sjulian /* 1775178888Sjulian * Correct length for chain is "count". 1776133387Sandre * Find the mbuf with last data, adjust its length, 1777133387Sandre * and toss data from remaining mbufs on chain. 1778133387Sandre */ 1779133387Sandre for (m = mp; m; m = m->m_next) { 1780117241Sluigi if (m->m_len >= count) { 1781171167Sgnn m->m_len = count; 1782117241Sluigi if (nul > 0) { 1783117241Sluigi cp = mtod(m, caddr_t)+m->m_len-nul; 1784117241Sluigi for (i = 0; i < nul; i++) 1785117241Sluigi *cp++ = '\0'; 1786117241Sluigi } 1787117241Sluigi break; 1788150122Sbz } 1789145246Sbrooks count -= m->m_len; 1790145246Sbrooks } 1791145246Sbrooks for (m = m->m_next;m;m = m->m_next) 1792145246Sbrooks m->m_len = 0; 1793145246Sbrooks} 1794145246Sbrooks 1795145246Sbrooks/* 1796145246Sbrooks * Make these functions instead of macros, so that the kernel text size 1797145246Sbrooks * doesn't get too big... 1798145246Sbrooks */ 1799145246Sbrooksvoid 1800145246Sbrooksnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 1801145246Sbrooks struct nfsrv_descript *nfsd; 1802145246Sbrooks int before_ret; 1803162351Sjhay register struct vattr *before_vap; 1804162351Sjhay int after_ret; 1805162351Sjhay struct vattr *after_vap; 1806162351Sjhay struct mbuf **mbp; 1807145246Sbrooks char **bposp; 1808162351Sjhay{ 1809162351Sjhay register struct mbuf *mb = *mbp, *mb2; 1810162351Sjhay register char *bpos = *bposp; 1811162351Sjhay register u_int32_t *tl; 1812162351Sjhay 1813162351Sjhay if (before_ret) { 1814162351Sjhay nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1815162351Sjhay *tl = nfs_false; 1816162351Sjhay } else { 1817162351Sjhay nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 1818162351Sjhay *tl++ = nfs_true; 1819162351Sjhay txdr_hyper(before_vap->va_size, tl); 1820145246Sbrooks tl += 2; 1821145246Sbrooks txdr_nfsv3time(&(before_vap->va_mtime), tl); 1822145246Sbrooks tl += 2; 1823145246Sbrooks txdr_nfsv3time(&(before_vap->va_ctime), tl); 1824145246Sbrooks } 1825145246Sbrooks *bposp = bpos; 1826145246Sbrooks *mbp = mb; 1827145246Sbrooks nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1828145246Sbrooks} 1829145246Sbrooks 1830145246Sbrooksvoid 1831145246Sbrooksnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 1832145246Sbrooks struct nfsrv_descript *nfsd; 1833145246Sbrooks int after_ret; 1834145246Sbrooks struct vattr *after_vap; 1835145246Sbrooks struct mbuf **mbp; 1836145246Sbrooks char **bposp; 1837145266Sphk{ 1838145246Sbrooks register struct mbuf *mb = *mbp, *mb2; 1839146894Smlaier register char *bpos = *bposp; 1840146894Smlaier register u_int32_t *tl; 1841146894Smlaier register struct nfs_fattr *fp; 1842146894Smlaier 1843159636Soleg if (after_ret) { 1844201527Sluigi nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1845159636Soleg *tl = nfs_false; 1846159636Soleg } else { 1847159636Soleg nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1848158879Soleg *tl++ = nfs_true; 1849159636Soleg fp = (struct nfs_fattr *)tl; 1850159636Soleg nfsm_srvfattr(nfsd, after_vap, fp); 1851158879Soleg } 1852158879Soleg *mbp = mb; 1853158879Soleg *bposp = bpos; 1854158879Soleg} 1855158879Soleg 1856158879Solegvoid 1857158879Solegnfsm_srvfattr(nfsd, vap, fp) 1858158879Soleg register struct nfsrv_descript *nfsd; 1859158879Soleg register struct vattr *vap; 1860158879Soleg register struct nfs_fattr *fp; 1861201527Sluigi{ 1862220568Sae 1863220568Sae fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1864220568Sae fp->fa_uid = txdr_unsigned(vap->va_uid); 1865220568Sae fp->fa_gid = txdr_unsigned(vap->va_gid); 1866220568Sae if (nfsd->nd_flag & ND_NFSV3) { 1867220568Sae fp->fa_type = vtonfsv3_type(vap->va_type); 1868220568Sae fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1869201527Sluigi txdr_hyper(vap->va_size, &fp->fa3_size); 1870158879Soleg txdr_hyper(vap->va_bytes, &fp->fa3_used); 1871158879Soleg fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 1872159636Soleg fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 1873158879Soleg fp->fa3_fsid.nfsuquad[0] = 0; 1874178888Sjulian fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1875178888Sjulian fp->fa3_fileid.nfsuquad[0] = 0; 1876178888Sjulian fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1877178888Sjulian txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1878178888Sjulian txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1879215179Sluigi txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1880215179Sluigi } else { 1881215179Sluigi fp->fa_type = vtonfsv2_type(vap->va_type); 1882215179Sluigi fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1883215179Sluigi fp->fa2_size = txdr_unsigned(vap->va_size); 1884215179Sluigi fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1885215179Sluigi if (vap->va_type == VFIFO) 1886215179Sluigi fp->fa2_rdev = 0xffffffff; 1887215179Sluigi else 1888215179Sluigi fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1889215179Sluigi fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1890215179Sluigi fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1891215179Sluigi fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1892215179Sluigi txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1893222488Srwatson txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1894222488Srwatson txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1895222488Srwatson } 1896222488Srwatson} 1897222488Srwatson 1898215179Sluigi/* 1899215179Sluigi * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1900215179Sluigi * - look up fsid in mount list (if not found ret error) 1901222488Srwatson * - get vp and export rights by calling VFS_FHTOVP() 1902215179Sluigi * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1903215179Sluigi * - if not lockflag unlock it with VOP_UNLOCK() 1904222488Srwatson */ 1905222488Srwatsonint 1906222488Srwatsonnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 1907222488Srwatson fhandle_t *fhp; 1908222488Srwatson int lockflag; 1909222488Srwatson struct vnode **vpp; 1910222488Srwatson struct ucred *cred; 1911222488Srwatson struct nfssvc_sock *slp; 1912222488Srwatson struct sockaddr *nam; 1913222488Srwatson int *rdonlyp; 1914222488Srwatson int kerbflag; 1915222488Srwatson int pubflag; 1916222488Srwatson{ 1917222488Srwatson struct proc *p = curproc; /* XXX */ 1918222488Srwatson register struct mount *mp; 1919215179Sluigi register int i; 1920215179Sluigi struct ucred *credanon; 1921215179Sluigi int error, exflags; 1922215179Sluigi#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1923159636Soleg struct sockaddr_int *saddr; 1924201527Sluigi#endif 1925159636Soleg 1926159636Soleg *vpp = (struct vnode *)0; 1927159636Soleg 1928158879Soleg if (nfs_ispublicfh(fhp)) { 1929159636Soleg if (!pubflag || !nfs_pub.np_valid) 1930159636Soleg return (ESTALE); 1931158879Soleg fhp = &nfs_pub.np_handle; 1932158879Soleg } 1933158879Soleg 1934158879Soleg mp = vfs_getvfs(&fhp->fh_fsid); 1935158879Soleg if (!mp) 1936158879Soleg return (ESTALE); 1937158879Soleg error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1938158879Soleg if (error) 1939158879Soleg return (error); 1940158879Soleg error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1941158879Soleg if (error) 1942158879Soleg return (error); 1943158879Soleg#ifdef MNT_EXNORESPORT 1944158879Soleg if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1945158879Soleg saddr = (struct sockaddr_in *)nam; 1946158879Soleg if (saddr->sin_family == AF_INET && 1947158879Soleg ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1948158879Soleg vput(*vpp); 1949158879Soleg *vpp = NULL; 1950158879Soleg return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1951158879Soleg } 1952159636Soleg } 1953158879Soleg#endif 195499622Sluigi /* 195599622Sluigi * Check/setup credentials. 195699622Sluigi */ 195799622Sluigi if (exflags & MNT_EXKERB) { 195899622Sluigi if (!kerbflag) { 195999622Sluigi vput(*vpp); 196099622Sluigi *vpp = NULL; 196199622Sluigi return (NFSERR_AUTHERR | AUTH_TOOWEAK); 196299622Sluigi } 196399622Sluigi } else if (kerbflag) { 1964200059Sluigi vput(*vpp); 196599622Sluigi *vpp = NULL; 196699622Sluigi return (NFSERR_AUTHERR | AUTH_TOOWEAK); 196799622Sluigi } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 196899622Sluigi cred->cr_uid = credanon->cr_uid; 1969200855Sluigi for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1970200855Sluigi cred->cr_groups[i] = credanon->cr_groups[i]; 197199622Sluigi cred->cr_ngroups = i; 1972158879Soleg } 1973136071Sgreen if (exflags & MNT_EXRDONLY) 1974136071Sgreen *rdonlyp = 1; 197599622Sluigi else 197699622Sluigi *rdonlyp = 0; 197799622Sluigi 197899622Sluigi nfsrv_object_create(*vpp); 197999622Sluigi 198099622Sluigi if (!lockflag) 1981200059Sluigi VOP_UNLOCK(*vpp, 0, p); 1982200059Sluigi return (0); 198399622Sluigi} 198499622Sluigi 198599622Sluigi 198699622Sluigi/* 1987200059Sluigi * WebNFS: check if a filehandle is a public filehandle. For v3, this 198899622Sluigi * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 1989200059Sluigi * transformed this to all zeroes in both cases, so check for it. 1990200059Sluigi */ 1991200059Sluigiint 1992200059Sluiginfs_ispublicfh(fhp) 1993200059Sluigi fhandle_t *fhp; 199499622Sluigi{ 199598943Sluigi char *cp = (char *)fhp; 199698943Sluigi int i; 1997200601Sluigi 1998159636Soleg for (i = 0; i < NFSX_V3FH; i++) 1999200059Sluigi if (*cp++ != 0) 2000140224Sglebius return (FALSE); 2001200059Sluigi return (TRUE); 2002200059Sluigi} 200399622Sluigi 200499622Sluigi#endif /* NFS_NOSERVER */ 200599622Sluigi/* 200698943Sluigi * This function compares two net addresses by family and returns TRUE 200798943Sluigi * if they are the same host. 200898943Sluigi * If there is any doubt, return FALSE. 200998943Sluigi * The AF_INET family is handled as a special case so that address mbufs 201098943Sluigi * don't need to be saved to store "struct in_addr", which is only 4 bytes. 201199622Sluigi */ 201299622Sluigiint 201399622Sluiginetaddr_match(family, haddr, nam) 201498943Sluigi int family; 201599622Sluigi union nethostaddr *haddr; 201698943Sluigi struct sockaddr *nam; 201798943Sluigi{ 201899622Sluigi register struct sockaddr_in *inetaddr; 2019200601Sluigi 2020100004Sluigi switch (family) { 2021145093Sbrooks case AF_INET: 2022100004Sluigi inetaddr = (struct sockaddr_in *)nam; 202399622Sluigi if (inetaddr->sin_family == AF_INET && 202499622Sluigi inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 202599622Sluigi return (1); 2026200059Sluigi break; 2027200059Sluigi default: 202899622Sluigi break; 202999622Sluigi }; 2030115750Skbyanc return (0); 2031200855Sluigi} 2032200855Sluigi 2033200855Sluigistatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 2034200855Sluigi/* 2035200855Sluigi * This function finds the directory cookie that corresponds to the 203699622Sluigi * logical byte offset given. 2037200855Sluigi */ 2038200855Sluiginfsuint64 * 203999622Sluiginfs_getcookie(np, off, add) 204099622Sluigi register struct nfsnode *np; 2041200580Sluigi off_t off; 2042200059Sluigi int add; 2043200059Sluigi{ 2044200059Sluigi register struct nfsdmap *dp, *dp2; 204598943Sluigi register int pos; 204699622Sluigi 204799622Sluigi pos = (uoff_t)off / NFS_DIRBLKSIZ; 204899622Sluigi if (pos == 0 || off < 0) { 204999622Sluigi#ifdef DIAGNOSTIC 205099622Sluigi if (add) 205198943Sluigi panic("nfs getcookie add at <= 0"); 2052200059Sluigi#endif 205399622Sluigi return (&nfs_nullcookie); 205499622Sluigi } 205598943Sluigi pos--; 205698943Sluigi dp = np->n_cookies.lh_first; 205798943Sluigi if (!dp) { 2058200059Sluigi if (add) { 2059200059Sluigi MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 2060200059Sluigi M_NFSDIROFF, M_WAITOK); 206198943Sluigi dp->ndm_eocookie = 0; 206298943Sluigi LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 206398943Sluigi } else 2064200855Sluigi return ((nfsuint64 *)0); 2065201527Sluigi } 2066200838Sluigi while (pos >= NFSNUMCOOKIES) { 2067201527Sluigi pos -= NFSNUMCOOKIES; 2068201527Sluigi if (dp->ndm_list.le_next) { 2069201527Sluigi if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 2070201527Sluigi pos >= dp->ndm_eocookie) 2071140224Sglebius return ((nfsuint64 *)0); 2072200059Sluigi dp = dp->ndm_list.le_next; 2073200059Sluigi } else if (add) { 2074200059Sluigi MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 2075105775Smaxim M_NFSDIROFF, M_WAITOK); 207698943Sluigi dp2->ndm_eocookie = 0; 2077200059Sluigi LIST_INSERT_AFTER(dp, dp2, ndm_list); 207898943Sluigi dp = dp2; 2079200059Sluigi } else 2080200059Sluigi return ((nfsuint64 *)0); 2081200059Sluigi } 2082200059Sluigi if (pos >= dp->ndm_eocookie) { 2083201527Sluigi if (add) 2084200059Sluigi dp->ndm_eocookie = pos + 1; 2085201527Sluigi else 2086201527Sluigi return ((nfsuint64 *)0); 2087201527Sluigi } 2088200059Sluigi return (&dp->ndm_cookies[pos]); 2089200059Sluigi} 209098943Sluigi 209198943Sluigi/* 2092115750Skbyanc * Invalidate cached directory information, except for the actual directory 2093150350Sandre * blocks (which are invalidated separately). 2094200896Sluigi * Done mainly to avoid the use of stale offset cookies. 2095200896Sluigi */ 2096200855Sluigivoid 2097200855Sluiginfs_invaldir(vp) 2098200855Sluigi register struct vnode *vp; 2099200855Sluigi{ 2100200855Sluigi register struct nfsnode *np = VTONFS(vp); 2101200855Sluigi 2102200855Sluigi#ifdef DIAGNOSTIC 2103200855Sluigi if (vp->v_type != VDIR) 2104200855Sluigi panic("nfs: invaldir not dir"); 2105200855Sluigi#endif 2106200896Sluigi np->n_direofoffset = 0; 2107200896Sluigi np->n_cookieverf.nfsuquad[0] = 0; 2108200855Sluigi np->n_cookieverf.nfsuquad[1] = 0; 2109200855Sluigi if (np->n_cookies.lh_first) 2110200855Sluigi np->n_cookies.lh_first->ndm_eocookie = 0; 2111200855Sluigi} 2112200855Sluigi 2113200855Sluigi/* 2114200855Sluigi * The write verifier has changed (probably due to a server reboot), so all 2115200855Sluigi * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 2116200855Sluigi * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 2117200896Sluigi * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 2118200855Sluigi * mount point. 2119200855Sluigi * 2120200855Sluigi * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 2121181139Sjulian * writes are not clusterable. 2122200896Sluigi */ 2123200896Sluigivoid 2124200855Sluiginfs_clearcommit(mp) 2125200855Sluigi struct mount *mp; 2126200855Sluigi{ 2127200896Sluigi register struct vnode *vp, *nvp; 2128200896Sluigi register struct buf *bp, *nbp; 2129200855Sluigi int s; 2130200855Sluigi 2131200855Sluigi s = splbio(); 2132200855Sluigiloop: 2133200855Sluigi for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 2134209589Sglebius if (vp->v_mount != mp) /* Paranoia */ 2135200855Sluigi goto loop; 2136200896Sluigi nvp = vp->v_mntvnodes.le_next; 2137200896Sluigi for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 2138200896Sluigi nbp = TAILQ_NEXT(bp, b_vnbufs); 2139200896Sluigi if (BUF_REFCNT(bp) == 0 && 2140200896Sluigi (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 2141209589Sglebius == (B_DELWRI | B_NEEDCOMMIT)) 2142209589Sglebius bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 214398943Sluigi } 2144223666Sae } 2145223666Sae splx(s); 2146223666Sae} 2147223666Sae 2148223666Sae#ifndef NFS_NOSERVER 2149223666Sae/* 2150223666Sae * Map errnos to NFS error numbers. For Version 3 also filter out error 2151223666Sae * numbers not specified for the associated procedure. 2152223666Sae */ 2153223666Saeint 2154223666Saenfsrv_errmap(nd, err) 2155223666Sae struct nfsrv_descript *nd; 2156223666Sae register int err; 2157223666Sae{ 2158223666Sae register short *defaulterrp, *errp; 2159223666Sae 2160223666Sae if (nd->nd_flag & ND_NFSV3) { 2161223666Sae if (nd->nd_procnum <= NFSPROC_COMMIT) { 2162223666Sae errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 2163223666Sae while (*++errp) { 2164223666Sae if (*errp == err) 2165223666Sae return (err); 2166223666Sae else if (*errp > err) 2167223666Sae break; 2168223666Sae } 2169223666Sae return ((int)*defaulterrp); 2170223666Sae } else 2171223666Sae return (err & 0xffff); 2172223666Sae } 2173223666Sae if (err <= ELAST) 2174223666Sae return ((int)nfsrv_v2errmap[err - 1]); 2175223666Sae return (NFSERR_IO); 2176223666Sae} 2177223666Sae 2178223666Saeint 2179223666Saenfsrv_object_create(vp) 2180223666Sae struct vnode *vp; 2181223666Sae{ 2182223666Sae 2183223666Sae if (vp == NULL || vp->v_type != VREG) 2184223666Sae return (1); 2185223666Sae return (vfs_object_create(vp, curproc, 2186223666Sae curproc ? curproc->p_ucred : NULL)); 2187223666Sae} 2188223666Sae 2189223666Sae/* 2190223666Sae * Sort the group list in increasing numerical order. 2191223666Sae * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 2192223666Sae * that used to be here.) 2193223666Sae */ 2194223666Saevoid 2195223666Saenfsrvw_sort(list, num) 2196223666Sae register gid_t *list; 2197223666Sae register int num; 2198223666Sae{ 2199223666Sae register int i, j; 2200223666Sae gid_t v; 2201223666Sae 2202223666Sae /* Insertion sort. */ 2203223666Sae for (i = 1; i < num; i++) { 2204223666Sae v = list[i]; 2205223666Sae /* find correct slot for value v, moving others up */ 2206223666Sae for (j = i; --j >= 0 && v < list[j];) 2207223666Sae list[j + 1] = list[j]; 2208223666Sae list[j + 1] = v; 2209223666Sae } 2210223666Sae} 2211223666Sae 2212223666Sae/* 2213223666Sae * copy credentials making sure that the result can be compared with bcmp(). 2214223666Sae */ 2215223666Saevoid 2216223666Saenfsrv_setcred(incred, outcred) 2217223666Sae register struct ucred *incred, *outcred; 2218223666Sae{ 2219223666Sae register int i; 2220223666Sae 2221223666Sae bzero((caddr_t)outcred, sizeof (struct ucred)); 2222223666Sae outcred->cr_ref = 1; 2223223666Sae outcred->cr_uid = incred->cr_uid; 2224223666Sae outcred->cr_ngroups = incred->cr_ngroups; 2225223666Sae for (i = 0; i < incred->cr_ngroups; i++) 2226223666Sae outcred->cr_groups[i] = incred->cr_groups[i]; 2227223666Sae nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 2228223666Sae} 2229223666Sae#endif /* NFS_NOSERVER */ 2230223666Sae