nfs_srvsubs.c revision 48274
1284741Sdavidcs/* 2284741Sdavidcs * Copyright (c) 1989, 1993 3284741Sdavidcs * The Regents of the University of California. All rights reserved. 4284741Sdavidcs * 5284741Sdavidcs * This code is derived from software contributed to Berkeley by 6284741Sdavidcs * Rick Macklem at The University of Guelph. 7284741Sdavidcs * 8284741Sdavidcs * Redistribution and use in source and binary forms, with or without 9284741Sdavidcs * modification, are permitted provided that the following conditions 10284741Sdavidcs * are met: 11284741Sdavidcs * 1. Redistributions of source code must retain the above copyright 12284741Sdavidcs * notice, this list of conditions and the following disclaimer. 13284741Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright 14284741Sdavidcs * notice, this list of conditions and the following disclaimer in the 15284741Sdavidcs * documentation and/or other materials provided with the distribution. 16284741Sdavidcs * 3. All advertising materials mentioning features or use of this software 17284741Sdavidcs * must display the following acknowledgement: 18284741Sdavidcs * This product includes software developed by the University of 19284741Sdavidcs * California, Berkeley and its contributors. 20284741Sdavidcs * 4. Neither the name of the University nor the names of its contributors 21284741Sdavidcs * may be used to endorse or promote products derived from this software 22284741Sdavidcs * without specific prior written permission. 23284741Sdavidcs * 24284741Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25284741Sdavidcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26284741Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27284741Sdavidcs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28284741Sdavidcs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29284741Sdavidcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30284741Sdavidcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31284741Sdavidcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32284741Sdavidcs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33284741Sdavidcs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34284741Sdavidcs * SUCH DAMAGE. 35284741Sdavidcs * 36284741Sdavidcs * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 37284741Sdavidcs * $Id: nfs_subs.c,v 1.77 1999/06/26 02:46:30 mckusick Exp $ 38284741Sdavidcs */ 39284741Sdavidcs 40284741Sdavidcs/* 41284741Sdavidcs * These functions support the macros and help fiddle mbuf chains for 42284741Sdavidcs * the nfs op functions. They do things like create the rpc header and 43284741Sdavidcs * copy data between mbuf chains and uio lists. 44284741Sdavidcs */ 45284741Sdavidcs#include <sys/param.h> 46284741Sdavidcs#include <sys/systm.h> 47284741Sdavidcs#include <sys/kernel.h> 48284741Sdavidcs#include <sys/buf.h> 49284741Sdavidcs#include <sys/proc.h> 50284741Sdavidcs#include <sys/mount.h> 51284741Sdavidcs#include <sys/vnode.h> 52284741Sdavidcs#include <sys/namei.h> 53284741Sdavidcs#include <sys/mbuf.h> 54284741Sdavidcs#include <sys/socket.h> 55284741Sdavidcs#include <sys/stat.h> 56284741Sdavidcs#include <sys/malloc.h> 57284741Sdavidcs#include <sys/sysent.h> 58284741Sdavidcs#include <sys/syscall.h> 59284741Sdavidcs 60284741Sdavidcs#include <vm/vm.h> 61284741Sdavidcs#include <vm/vm_object.h> 62284741Sdavidcs#include <vm/vm_extern.h> 63284741Sdavidcs#include <vm/vm_zone.h> 64284741Sdavidcs 65284741Sdavidcs#include <nfs/rpcv2.h> 66284741Sdavidcs#include <nfs/nfsproto.h> 67284741Sdavidcs#include <nfs/nfs.h> 68284741Sdavidcs#include <nfs/nfsnode.h> 69284741Sdavidcs#include <nfs/xdr_subs.h> 70284741Sdavidcs#include <nfs/nfsm_subs.h> 71284741Sdavidcs#include <nfs/nfsmount.h> 72284741Sdavidcs#include <nfs/nqnfs.h> 73284741Sdavidcs#include <nfs/nfsrtt.h> 74284741Sdavidcs 75284741Sdavidcs#include <miscfs/specfs/specdev.h> 76284741Sdavidcs 77284741Sdavidcs#include <netinet/in.h> 78284741Sdavidcs#ifdef ISO 79284741Sdavidcs#include <netiso/iso.h> 80284741Sdavidcs#endif 81284741Sdavidcs 82284741Sdavidcs/* 83284741Sdavidcs * Data items converted to xdr at startup, since they are constant 84284741Sdavidcs * This is kinda hokey, but may save a little time doing byte swaps 85284741Sdavidcs */ 86284741Sdavidcsu_int32_t nfs_xdrneg1; 87284741Sdavidcsu_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 88284741Sdavidcs rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 89284741Sdavidcs rpc_auth_kerb; 90284741Sdavidcsu_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 91284741Sdavidcs 92284741Sdavidcs/* And other global data */ 93284741Sdavidcsstatic u_int32_t nfs_xid = 0; 94284741Sdavidcsstatic enum vtype nv2tov_type[8]= { 95284741Sdavidcs VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 96284741Sdavidcs}; 97284741Sdavidcsenum vtype nv3tov_type[8]= { 98284741Sdavidcs VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 99284741Sdavidcs}; 100284741Sdavidcs 101284741Sdavidcsint nfs_ticks; 102284741Sdavidcsint nfs_pbuf_freecnt = -1; /* start out unlimited */ 103284741Sdavidcs 104284741Sdavidcsstruct nfs_reqq nfs_reqq; 105284741Sdavidcsstruct nfssvc_sockhead nfssvc_sockhead; 106284741Sdavidcsint nfssvc_sockhead_flag; 107284741Sdavidcsstruct nfsd_head nfsd_head; 108284741Sdavidcsint nfsd_head_flag; 109284741Sdavidcsstruct nfs_bufq nfs_bufq; 110284741Sdavidcsstruct nqtimerhead nqtimerhead; 111284741Sdavidcsstruct nqfhhashhead *nqfhhashtbl; 112284741Sdavidcsu_long nqfhhash; 113284741Sdavidcs 114284741Sdavidcsstatic void (*nfs_prev_lease_updatetime) __P((int)); 115284741Sdavidcsstatic int nfs_prev_nfssvc_sy_narg; 116284741Sdavidcsstatic sy_call_t *nfs_prev_nfssvc_sy_call; 117284741Sdavidcs 118284741Sdavidcs#ifndef NFS_NOSERVER 119284741Sdavidcs 120284741Sdavidcsstatic vop_t *nfs_prev_vop_lease_check; 121284741Sdavidcsstatic int nfs_prev_getfh_sy_narg; 122284741Sdavidcsstatic sy_call_t *nfs_prev_getfh_sy_call; 123284741Sdavidcs 124284741Sdavidcs/* 125284741Sdavidcs * Mapping of old NFS Version 2 RPC numbers to generic numbers. 126284741Sdavidcs */ 127284741Sdavidcsint nfsv3_procid[NFS_NPROCS] = { 128284741Sdavidcs NFSPROC_NULL, 129284741Sdavidcs NFSPROC_GETATTR, 130284741Sdavidcs NFSPROC_SETATTR, 131284741Sdavidcs NFSPROC_NOOP, 132284741Sdavidcs NFSPROC_LOOKUP, 133284741Sdavidcs NFSPROC_READLINK, 134284741Sdavidcs NFSPROC_READ, 135284741Sdavidcs NFSPROC_NOOP, 136284741Sdavidcs NFSPROC_WRITE, 137284741Sdavidcs NFSPROC_CREATE, 138284741Sdavidcs NFSPROC_REMOVE, 139284741Sdavidcs NFSPROC_RENAME, 140284741Sdavidcs NFSPROC_LINK, 141284741Sdavidcs NFSPROC_SYMLINK, 142284741Sdavidcs NFSPROC_MKDIR, 143284741Sdavidcs NFSPROC_RMDIR, 144284741Sdavidcs NFSPROC_READDIR, 145284741Sdavidcs NFSPROC_FSSTAT, 146284741Sdavidcs NFSPROC_NOOP, 147284741Sdavidcs NFSPROC_NOOP, 148284741Sdavidcs NFSPROC_NOOP, 149284741Sdavidcs NFSPROC_NOOP, 150284741Sdavidcs NFSPROC_NOOP, 151284741Sdavidcs NFSPROC_NOOP, 152284741Sdavidcs NFSPROC_NOOP, 153284741Sdavidcs NFSPROC_NOOP 154284741Sdavidcs}; 155284741Sdavidcs 156284741Sdavidcs#endif /* NFS_NOSERVER */ 157284741Sdavidcs/* 158284741Sdavidcs * and the reverse mapping from generic to Version 2 procedure numbers 159284741Sdavidcs */ 160284741Sdavidcsint nfsv2_procid[NFS_NPROCS] = { 161284741Sdavidcs NFSV2PROC_NULL, 162284741Sdavidcs NFSV2PROC_GETATTR, 163284741Sdavidcs NFSV2PROC_SETATTR, 164284741Sdavidcs NFSV2PROC_LOOKUP, 165284741Sdavidcs NFSV2PROC_NOOP, 166284741Sdavidcs NFSV2PROC_READLINK, 167284741Sdavidcs NFSV2PROC_READ, 168284741Sdavidcs NFSV2PROC_WRITE, 169284741Sdavidcs NFSV2PROC_CREATE, 170284741Sdavidcs NFSV2PROC_MKDIR, 171284741Sdavidcs NFSV2PROC_SYMLINK, 172284741Sdavidcs NFSV2PROC_CREATE, 173284741Sdavidcs NFSV2PROC_REMOVE, 174284741Sdavidcs NFSV2PROC_RMDIR, 175284741Sdavidcs NFSV2PROC_RENAME, 176284741Sdavidcs NFSV2PROC_LINK, 177284741Sdavidcs NFSV2PROC_READDIR, 178284741Sdavidcs NFSV2PROC_NOOP, 179284741Sdavidcs NFSV2PROC_STATFS, 180284741Sdavidcs NFSV2PROC_NOOP, 181284741Sdavidcs NFSV2PROC_NOOP, 182284741Sdavidcs NFSV2PROC_NOOP, 183284741Sdavidcs NFSV2PROC_NOOP, 184284741Sdavidcs NFSV2PROC_NOOP, 185284741Sdavidcs NFSV2PROC_NOOP, 186284741Sdavidcs NFSV2PROC_NOOP, 187284741Sdavidcs}; 188284741Sdavidcs 189284741Sdavidcs#ifndef NFS_NOSERVER 190284741Sdavidcs/* 191284741Sdavidcs * Maps errno values to nfs error numbers. 192284741Sdavidcs * Use NFSERR_IO as the catch all for ones not specifically defined in 193284741Sdavidcs * RFC 1094. 194284741Sdavidcs */ 195284741Sdavidcsstatic u_char nfsrv_v2errmap[ELAST] = { 196284741Sdavidcs NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 197284741Sdavidcs NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 198284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 199284741Sdavidcs NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 200284741Sdavidcs NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 201284741Sdavidcs NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 202284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 203284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 204284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 205284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 206284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 207284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 208284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 209284741Sdavidcs NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 210284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 211284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 212284741Sdavidcs NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 213284741Sdavidcs NFSERR_IO /* << Last is 86 */ 214284741Sdavidcs}; 215284741Sdavidcs 216284741Sdavidcs/* 217284741Sdavidcs * Maps errno values to nfs error numbers. 218284741Sdavidcs * Although it is not obvious whether or not NFS clients really care if 219284741Sdavidcs * a returned error value is in the specified list for the procedure, the 220284741Sdavidcs * safest thing to do is filter them appropriately. For Version 2, the 221284741Sdavidcs * X/Open XNFS document is the only specification that defines error values 222284741Sdavidcs * for each RPC (The RFC simply lists all possible error values for all RPCs), 223284741Sdavidcs * so I have decided to not do this for Version 2. 224284741Sdavidcs * The first entry is the default error return and the rest are the valid 225284741Sdavidcs * errors for that RPC in increasing numeric order. 226284741Sdavidcs */ 227284741Sdavidcsstatic short nfsv3err_null[] = { 228284741Sdavidcs 0, 229284741Sdavidcs 0, 230284741Sdavidcs}; 231284741Sdavidcs 232284741Sdavidcsstatic short nfsv3err_getattr[] = { 233284741Sdavidcs NFSERR_IO, 234284741Sdavidcs NFSERR_IO, 235284741Sdavidcs NFSERR_STALE, 236284741Sdavidcs NFSERR_BADHANDLE, 237284741Sdavidcs NFSERR_SERVERFAULT, 238284741Sdavidcs 0, 239284741Sdavidcs}; 240284741Sdavidcs 241284741Sdavidcsstatic short nfsv3err_setattr[] = { 242284741Sdavidcs NFSERR_IO, 243284741Sdavidcs NFSERR_PERM, 244284741Sdavidcs NFSERR_IO, 245284741Sdavidcs NFSERR_ACCES, 246284741Sdavidcs NFSERR_INVAL, 247284741Sdavidcs NFSERR_NOSPC, 248284741Sdavidcs NFSERR_ROFS, 249284741Sdavidcs NFSERR_DQUOT, 250284741Sdavidcs NFSERR_STALE, 251284741Sdavidcs NFSERR_BADHANDLE, 252284741Sdavidcs NFSERR_NOT_SYNC, 253284741Sdavidcs NFSERR_SERVERFAULT, 254284741Sdavidcs 0, 255284741Sdavidcs}; 256284741Sdavidcs 257284741Sdavidcsstatic short nfsv3err_lookup[] = { 258284741Sdavidcs NFSERR_IO, 259284741Sdavidcs NFSERR_NOENT, 260284741Sdavidcs NFSERR_IO, 261284741Sdavidcs NFSERR_ACCES, 262284741Sdavidcs NFSERR_NOTDIR, 263284741Sdavidcs NFSERR_NAMETOL, 264284741Sdavidcs NFSERR_STALE, 265284741Sdavidcs NFSERR_BADHANDLE, 266284741Sdavidcs NFSERR_SERVERFAULT, 267284741Sdavidcs 0, 268284741Sdavidcs}; 269284741Sdavidcs 270284741Sdavidcsstatic short nfsv3err_access[] = { 271284741Sdavidcs NFSERR_IO, 272284741Sdavidcs NFSERR_IO, 273284741Sdavidcs NFSERR_STALE, 274284741Sdavidcs NFSERR_BADHANDLE, 275284741Sdavidcs NFSERR_SERVERFAULT, 276284741Sdavidcs 0, 277284741Sdavidcs}; 278284741Sdavidcs 279284741Sdavidcsstatic short nfsv3err_readlink[] = { 280284741Sdavidcs NFSERR_IO, 281284741Sdavidcs NFSERR_IO, 282284741Sdavidcs NFSERR_ACCES, 283284741Sdavidcs NFSERR_INVAL, 284284741Sdavidcs NFSERR_STALE, 285284741Sdavidcs NFSERR_BADHANDLE, 286284741Sdavidcs NFSERR_NOTSUPP, 287284741Sdavidcs NFSERR_SERVERFAULT, 288284741Sdavidcs 0, 289284741Sdavidcs}; 290284741Sdavidcs 291284741Sdavidcsstatic short nfsv3err_read[] = { 292284741Sdavidcs NFSERR_IO, 293284741Sdavidcs NFSERR_IO, 294284741Sdavidcs NFSERR_NXIO, 295284741Sdavidcs NFSERR_ACCES, 296284741Sdavidcs NFSERR_INVAL, 297284741Sdavidcs NFSERR_STALE, 298284741Sdavidcs NFSERR_BADHANDLE, 299284741Sdavidcs NFSERR_SERVERFAULT, 300284741Sdavidcs 0, 301284741Sdavidcs}; 302284741Sdavidcs 303284741Sdavidcsstatic short nfsv3err_write[] = { 304284741Sdavidcs NFSERR_IO, 305284741Sdavidcs NFSERR_IO, 306284741Sdavidcs NFSERR_ACCES, 307284741Sdavidcs NFSERR_INVAL, 308284741Sdavidcs NFSERR_FBIG, 309284741Sdavidcs NFSERR_NOSPC, 310284741Sdavidcs NFSERR_ROFS, 311284741Sdavidcs NFSERR_DQUOT, 312284741Sdavidcs NFSERR_STALE, 313284741Sdavidcs NFSERR_BADHANDLE, 314284741Sdavidcs NFSERR_SERVERFAULT, 315284741Sdavidcs 0, 316284741Sdavidcs}; 317284741Sdavidcs 318284741Sdavidcsstatic short nfsv3err_create[] = { 319284741Sdavidcs NFSERR_IO, 320284741Sdavidcs NFSERR_IO, 321284741Sdavidcs NFSERR_ACCES, 322284741Sdavidcs NFSERR_EXIST, 323284741Sdavidcs NFSERR_NOTDIR, 324284741Sdavidcs NFSERR_NOSPC, 325284741Sdavidcs NFSERR_ROFS, 326284741Sdavidcs NFSERR_NAMETOL, 327284741Sdavidcs NFSERR_DQUOT, 328284741Sdavidcs NFSERR_STALE, 329284741Sdavidcs NFSERR_BADHANDLE, 330284741Sdavidcs NFSERR_NOTSUPP, 331284741Sdavidcs NFSERR_SERVERFAULT, 332284741Sdavidcs 0, 333284741Sdavidcs}; 334284741Sdavidcs 335284741Sdavidcsstatic short nfsv3err_mkdir[] = { 336284741Sdavidcs NFSERR_IO, 337284741Sdavidcs NFSERR_IO, 338284741Sdavidcs NFSERR_ACCES, 339284741Sdavidcs NFSERR_EXIST, 340284741Sdavidcs NFSERR_NOTDIR, 341284741Sdavidcs NFSERR_NOSPC, 342284741Sdavidcs NFSERR_ROFS, 343284741Sdavidcs NFSERR_NAMETOL, 344284741Sdavidcs NFSERR_DQUOT, 345284741Sdavidcs NFSERR_STALE, 346284741Sdavidcs NFSERR_BADHANDLE, 347284741Sdavidcs NFSERR_NOTSUPP, 348284741Sdavidcs NFSERR_SERVERFAULT, 349284741Sdavidcs 0, 350284741Sdavidcs}; 351284741Sdavidcs 352284741Sdavidcsstatic short nfsv3err_symlink[] = { 353284741Sdavidcs NFSERR_IO, 354284741Sdavidcs NFSERR_IO, 355284741Sdavidcs NFSERR_ACCES, 356284741Sdavidcs NFSERR_EXIST, 357284741Sdavidcs NFSERR_NOTDIR, 358284741Sdavidcs NFSERR_NOSPC, 359284741Sdavidcs NFSERR_ROFS, 360284741Sdavidcs NFSERR_NAMETOL, 361284741Sdavidcs NFSERR_DQUOT, 362284741Sdavidcs NFSERR_STALE, 363284741Sdavidcs NFSERR_BADHANDLE, 364284741Sdavidcs NFSERR_NOTSUPP, 365284741Sdavidcs NFSERR_SERVERFAULT, 366284741Sdavidcs 0, 367284741Sdavidcs}; 368284741Sdavidcs 369284741Sdavidcsstatic short nfsv3err_mknod[] = { 370284741Sdavidcs NFSERR_IO, 371284741Sdavidcs NFSERR_IO, 372284741Sdavidcs NFSERR_ACCES, 373284741Sdavidcs NFSERR_EXIST, 374284741Sdavidcs NFSERR_NOTDIR, 375284741Sdavidcs NFSERR_NOSPC, 376284741Sdavidcs NFSERR_ROFS, 377284741Sdavidcs NFSERR_NAMETOL, 378284741Sdavidcs NFSERR_DQUOT, 379284741Sdavidcs NFSERR_STALE, 380284741Sdavidcs NFSERR_BADHANDLE, 381284741Sdavidcs NFSERR_NOTSUPP, 382284741Sdavidcs NFSERR_SERVERFAULT, 383284741Sdavidcs NFSERR_BADTYPE, 384284741Sdavidcs 0, 385284741Sdavidcs}; 386284741Sdavidcs 387284741Sdavidcsstatic short nfsv3err_remove[] = { 388284741Sdavidcs NFSERR_IO, 389284741Sdavidcs NFSERR_NOENT, 390284741Sdavidcs NFSERR_IO, 391284741Sdavidcs NFSERR_ACCES, 392284741Sdavidcs NFSERR_NOTDIR, 393284741Sdavidcs NFSERR_ROFS, 394284741Sdavidcs NFSERR_NAMETOL, 395284741Sdavidcs NFSERR_STALE, 396284741Sdavidcs NFSERR_BADHANDLE, 397284741Sdavidcs NFSERR_SERVERFAULT, 398284741Sdavidcs 0, 399284741Sdavidcs}; 400284741Sdavidcs 401284741Sdavidcsstatic short nfsv3err_rmdir[] = { 402284741Sdavidcs NFSERR_IO, 403284741Sdavidcs NFSERR_NOENT, 404284741Sdavidcs NFSERR_IO, 405284741Sdavidcs NFSERR_ACCES, 406284741Sdavidcs NFSERR_EXIST, 407284741Sdavidcs NFSERR_NOTDIR, 408284741Sdavidcs NFSERR_INVAL, 409284741Sdavidcs NFSERR_ROFS, 410284741Sdavidcs NFSERR_NAMETOL, 411284741Sdavidcs NFSERR_NOTEMPTY, 412284741Sdavidcs NFSERR_STALE, 413284741Sdavidcs NFSERR_BADHANDLE, 414284741Sdavidcs NFSERR_NOTSUPP, 415284741Sdavidcs NFSERR_SERVERFAULT, 416284741Sdavidcs 0, 417284741Sdavidcs}; 418284741Sdavidcs 419284741Sdavidcsstatic short nfsv3err_rename[] = { 420284741Sdavidcs NFSERR_IO, 421284741Sdavidcs NFSERR_NOENT, 422284741Sdavidcs NFSERR_IO, 423284741Sdavidcs NFSERR_ACCES, 424284741Sdavidcs NFSERR_EXIST, 425284741Sdavidcs NFSERR_XDEV, 426284741Sdavidcs NFSERR_NOTDIR, 427284741Sdavidcs NFSERR_ISDIR, 428284741Sdavidcs NFSERR_INVAL, 429284741Sdavidcs NFSERR_NOSPC, 430284741Sdavidcs NFSERR_ROFS, 431284741Sdavidcs NFSERR_MLINK, 432284741Sdavidcs NFSERR_NAMETOL, 433284741Sdavidcs NFSERR_NOTEMPTY, 434284741Sdavidcs NFSERR_DQUOT, 435284741Sdavidcs NFSERR_STALE, 436284741Sdavidcs NFSERR_BADHANDLE, 437284741Sdavidcs NFSERR_NOTSUPP, 438284741Sdavidcs NFSERR_SERVERFAULT, 439284741Sdavidcs 0, 440284741Sdavidcs}; 441284741Sdavidcs 442284741Sdavidcsstatic short nfsv3err_link[] = { 443284741Sdavidcs NFSERR_IO, 444284741Sdavidcs NFSERR_IO, 445284741Sdavidcs NFSERR_ACCES, 446284741Sdavidcs NFSERR_EXIST, 447284741Sdavidcs NFSERR_XDEV, 448284741Sdavidcs NFSERR_NOTDIR, 449284741Sdavidcs NFSERR_INVAL, 450284741Sdavidcs NFSERR_NOSPC, 451284741Sdavidcs NFSERR_ROFS, 452284741Sdavidcs NFSERR_MLINK, 453284741Sdavidcs NFSERR_NAMETOL, 454284741Sdavidcs NFSERR_DQUOT, 455284741Sdavidcs NFSERR_STALE, 456284741Sdavidcs NFSERR_BADHANDLE, 457284741Sdavidcs NFSERR_NOTSUPP, 458284741Sdavidcs NFSERR_SERVERFAULT, 459284741Sdavidcs 0, 460284741Sdavidcs}; 461284741Sdavidcs 462284741Sdavidcsstatic short nfsv3err_readdir[] = { 463284741Sdavidcs NFSERR_IO, 464284741Sdavidcs NFSERR_IO, 465284741Sdavidcs NFSERR_ACCES, 466284741Sdavidcs NFSERR_NOTDIR, 467284741Sdavidcs NFSERR_STALE, 468284741Sdavidcs NFSERR_BADHANDLE, 469284741Sdavidcs NFSERR_BAD_COOKIE, 470284741Sdavidcs NFSERR_TOOSMALL, 471284741Sdavidcs NFSERR_SERVERFAULT, 472284741Sdavidcs 0, 473284741Sdavidcs}; 474284741Sdavidcs 475284741Sdavidcsstatic short nfsv3err_readdirplus[] = { 476284741Sdavidcs NFSERR_IO, 477284741Sdavidcs NFSERR_IO, 478284741Sdavidcs NFSERR_ACCES, 479284741Sdavidcs NFSERR_NOTDIR, 480284741Sdavidcs NFSERR_STALE, 481284741Sdavidcs NFSERR_BADHANDLE, 482284741Sdavidcs NFSERR_BAD_COOKIE, 483284741Sdavidcs NFSERR_NOTSUPP, 484284741Sdavidcs NFSERR_TOOSMALL, 485284741Sdavidcs NFSERR_SERVERFAULT, 486284741Sdavidcs 0, 487284741Sdavidcs}; 488284741Sdavidcs 489284741Sdavidcsstatic short nfsv3err_fsstat[] = { 490284741Sdavidcs NFSERR_IO, 491284741Sdavidcs NFSERR_IO, 492284741Sdavidcs NFSERR_STALE, 493284741Sdavidcs NFSERR_BADHANDLE, 494284741Sdavidcs NFSERR_SERVERFAULT, 495284741Sdavidcs 0, 496284741Sdavidcs}; 497284741Sdavidcs 498284741Sdavidcsstatic short nfsv3err_fsinfo[] = { 499284741Sdavidcs NFSERR_STALE, 500284741Sdavidcs NFSERR_STALE, 501284741Sdavidcs NFSERR_BADHANDLE, 502284741Sdavidcs NFSERR_SERVERFAULT, 503284741Sdavidcs 0, 504284741Sdavidcs}; 505284741Sdavidcs 506284741Sdavidcsstatic short nfsv3err_pathconf[] = { 507284741Sdavidcs NFSERR_STALE, 508284741Sdavidcs NFSERR_STALE, 509284741Sdavidcs NFSERR_BADHANDLE, 510284741Sdavidcs NFSERR_SERVERFAULT, 511284741Sdavidcs 0, 512284741Sdavidcs}; 513284741Sdavidcs 514284741Sdavidcsstatic short nfsv3err_commit[] = { 515284741Sdavidcs NFSERR_IO, 516284741Sdavidcs NFSERR_IO, 517284741Sdavidcs NFSERR_STALE, 518284741Sdavidcs NFSERR_BADHANDLE, 519284741Sdavidcs NFSERR_SERVERFAULT, 520284741Sdavidcs 0, 521284741Sdavidcs}; 522284741Sdavidcs 523284741Sdavidcsstatic short *nfsrv_v3errmap[] = { 524284741Sdavidcs nfsv3err_null, 525284741Sdavidcs nfsv3err_getattr, 526284741Sdavidcs nfsv3err_setattr, 527284741Sdavidcs nfsv3err_lookup, 528284741Sdavidcs nfsv3err_access, 529284741Sdavidcs nfsv3err_readlink, 530284741Sdavidcs nfsv3err_read, 531284741Sdavidcs nfsv3err_write, 532284741Sdavidcs nfsv3err_create, 533284741Sdavidcs nfsv3err_mkdir, 534284741Sdavidcs nfsv3err_symlink, 535284741Sdavidcs nfsv3err_mknod, 536284741Sdavidcs nfsv3err_remove, 537284741Sdavidcs nfsv3err_rmdir, 538284741Sdavidcs nfsv3err_rename, 539284741Sdavidcs nfsv3err_link, 540284741Sdavidcs nfsv3err_readdir, 541284741Sdavidcs nfsv3err_readdirplus, 542284741Sdavidcs nfsv3err_fsstat, 543284741Sdavidcs nfsv3err_fsinfo, 544284741Sdavidcs nfsv3err_pathconf, 545284741Sdavidcs nfsv3err_commit, 546284741Sdavidcs}; 547284741Sdavidcs 548284741Sdavidcs#endif /* NFS_NOSERVER */ 549284741Sdavidcs 550284741Sdavidcsextern struct nfsrtt nfsrtt; 551284741Sdavidcsextern time_t nqnfsstarttime; 552284741Sdavidcsextern int nqsrv_clockskew; 553284741Sdavidcsextern int nqsrv_writeslack; 554284741Sdavidcsextern int nqsrv_maxlease; 555284741Sdavidcsextern struct nfsstats nfsstats; 556284741Sdavidcsextern int nqnfs_piggy[NFS_NPROCS]; 557284741Sdavidcsextern nfstype nfsv2_type[9]; 558284741Sdavidcsextern nfstype nfsv3_type[9]; 559284741Sdavidcsextern struct nfsnodehashhead *nfsnodehashtbl; 560284741Sdavidcsextern u_long nfsnodehash; 561284741Sdavidcs 562284741Sdavidcsstruct getfh_args; 563284741Sdavidcsextern int getfh(struct proc *, struct getfh_args *, int *); 564284741Sdavidcsstruct nfssvc_args; 565284741Sdavidcsextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 566284741Sdavidcs 567284741SdavidcsLIST_HEAD(nfsnodehashhead, nfsnode); 568284741Sdavidcs 569284741Sdavidcsint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 570284741Sdavidcs 571284741Sdavidcsu_quad_t 572284741Sdavidcsnfs_curusec() 573284741Sdavidcs{ 574284741Sdavidcs struct timeval tv; 575284741Sdavidcs 576284741Sdavidcs getmicrotime(&tv); 577284741Sdavidcs return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); 578284741Sdavidcs} 579284741Sdavidcs 580284741Sdavidcs/* 581284741Sdavidcs * Create the header for an rpc request packet 582284741Sdavidcs * The hsiz is the size of the rest of the nfs request header. 583284741Sdavidcs * (just used to decide if a cluster is a good idea) 584284741Sdavidcs */ 585284741Sdavidcsstruct mbuf * 586284741Sdavidcsnfsm_reqh(vp, procid, hsiz, bposp) 587284741Sdavidcs struct vnode *vp; 588284741Sdavidcs u_long procid; 589284741Sdavidcs int hsiz; 590284741Sdavidcs caddr_t *bposp; 591284741Sdavidcs{ 592284741Sdavidcs register struct mbuf *mb; 593284741Sdavidcs register u_int32_t *tl; 594284741Sdavidcs register caddr_t bpos; 595284741Sdavidcs struct mbuf *mb2; 596284741Sdavidcs struct nfsmount *nmp; 597284741Sdavidcs int nqflag; 598284741Sdavidcs 599284741Sdavidcs MGET(mb, M_WAIT, MT_DATA); 600284741Sdavidcs if (hsiz >= MINCLSIZE) 601284741Sdavidcs MCLGET(mb, M_WAIT); 602284741Sdavidcs mb->m_len = 0; 603284741Sdavidcs bpos = mtod(mb, caddr_t); 604284741Sdavidcs 605284741Sdavidcs /* 606284741Sdavidcs * For NQNFS, add lease request. 607284741Sdavidcs */ 608284741Sdavidcs if (vp) { 609284741Sdavidcs nmp = VFSTONFS(vp->v_mount); 610284741Sdavidcs if (nmp->nm_flag & NFSMNT_NQNFS) { 611284741Sdavidcs nqflag = NQNFS_NEEDLEASE(vp, procid); 612284741Sdavidcs if (nqflag) { 613284741Sdavidcs nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 614284741Sdavidcs *tl++ = txdr_unsigned(nqflag); 615284741Sdavidcs *tl = txdr_unsigned(nmp->nm_leaseterm); 616284741Sdavidcs } else { 617284741Sdavidcs nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 618284741Sdavidcs *tl = 0; 619284741Sdavidcs } 620284741Sdavidcs } 621284741Sdavidcs } 622284741Sdavidcs /* Finally, return values */ 623284741Sdavidcs *bposp = bpos; 624284741Sdavidcs return (mb); 625284741Sdavidcs} 626284741Sdavidcs 627284741Sdavidcs/* 628284741Sdavidcs * Build the RPC header and fill in the authorization info. 629284741Sdavidcs * The authorization string argument is only used when the credentials 630284741Sdavidcs * come from outside of the kernel. 631284741Sdavidcs * Returns the head of the mbuf list. 632284741Sdavidcs */ 633284741Sdavidcsstruct mbuf * 634284741Sdavidcsnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 635284741Sdavidcs verf_str, mrest, mrest_len, mbp, xidp) 636284741Sdavidcs register struct ucred *cr; 637284741Sdavidcs int nmflag; 638284741Sdavidcs int procid; 639284741Sdavidcs int auth_type; 640284741Sdavidcs int auth_len; 641284741Sdavidcs char *auth_str; 642284741Sdavidcs int verf_len; 643284741Sdavidcs char *verf_str; 644284741Sdavidcs struct mbuf *mrest; 645284741Sdavidcs int mrest_len; 646284741Sdavidcs struct mbuf **mbp; 647284741Sdavidcs u_int32_t *xidp; 648284741Sdavidcs{ 649284741Sdavidcs register struct mbuf *mb; 650284741Sdavidcs register u_int32_t *tl; 651284741Sdavidcs register caddr_t bpos; 652284741Sdavidcs register int i; 653284741Sdavidcs struct mbuf *mreq, *mb2; 654284741Sdavidcs int siz, grpsiz, authsiz; 655284741Sdavidcs 656284741Sdavidcs authsiz = nfsm_rndup(auth_len); 657284741Sdavidcs MGETHDR(mb, M_WAIT, MT_DATA); 658284741Sdavidcs if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 659284741Sdavidcs MCLGET(mb, M_WAIT); 660284741Sdavidcs } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 661284741Sdavidcs MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 662284741Sdavidcs } else { 663284741Sdavidcs MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 664284741Sdavidcs } 665284741Sdavidcs mb->m_len = 0; 666284741Sdavidcs mreq = mb; 667284741Sdavidcs bpos = mtod(mb, caddr_t); 668284741Sdavidcs 669284741Sdavidcs /* 670284741Sdavidcs * First the RPC header. 671284741Sdavidcs */ 672284741Sdavidcs nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 673284741Sdavidcs 674284741Sdavidcs /* Get a pretty random xid to start with */ 675284741Sdavidcs if (!nfs_xid) 676284741Sdavidcs nfs_xid = random(); 677284741Sdavidcs /* 678284741Sdavidcs * Skip zero xid if it should ever happen. 679284741Sdavidcs */ 680284741Sdavidcs if (++nfs_xid == 0) 681284741Sdavidcs nfs_xid++; 682284741Sdavidcs 683284741Sdavidcs *tl++ = *xidp = txdr_unsigned(nfs_xid); 684284741Sdavidcs *tl++ = rpc_call; 685284741Sdavidcs *tl++ = rpc_vers; 686284741Sdavidcs if (nmflag & NFSMNT_NQNFS) { 687284741Sdavidcs *tl++ = txdr_unsigned(NQNFS_PROG); 688284741Sdavidcs *tl++ = txdr_unsigned(NQNFS_VER3); 689284741Sdavidcs } else { 690284741Sdavidcs *tl++ = txdr_unsigned(NFS_PROG); 691284741Sdavidcs if (nmflag & NFSMNT_NFSV3) 692284741Sdavidcs *tl++ = txdr_unsigned(NFS_VER3); 693284741Sdavidcs else 694284741Sdavidcs *tl++ = txdr_unsigned(NFS_VER2); 695284741Sdavidcs } 696284741Sdavidcs if (nmflag & NFSMNT_NFSV3) 697284741Sdavidcs *tl++ = txdr_unsigned(procid); 698284741Sdavidcs else 699284741Sdavidcs *tl++ = txdr_unsigned(nfsv2_procid[procid]); 700284741Sdavidcs 701284741Sdavidcs /* 702284741Sdavidcs * And then the authorization cred. 703284741Sdavidcs */ 704284741Sdavidcs *tl++ = txdr_unsigned(auth_type); 705284741Sdavidcs *tl = txdr_unsigned(authsiz); 706284741Sdavidcs switch (auth_type) { 707284741Sdavidcs case RPCAUTH_UNIX: 708284741Sdavidcs nfsm_build(tl, u_int32_t *, auth_len); 709284741Sdavidcs *tl++ = 0; /* stamp ?? */ 710284741Sdavidcs *tl++ = 0; /* NULL hostname */ 711284741Sdavidcs *tl++ = txdr_unsigned(cr->cr_uid); 712284741Sdavidcs *tl++ = txdr_unsigned(cr->cr_groups[0]); 713284741Sdavidcs grpsiz = (auth_len >> 2) - 5; 714284741Sdavidcs *tl++ = txdr_unsigned(grpsiz); 715284741Sdavidcs for (i = 1; i <= grpsiz; i++) 716284741Sdavidcs *tl++ = txdr_unsigned(cr->cr_groups[i]); 717284741Sdavidcs break; 718284741Sdavidcs case RPCAUTH_KERB4: 719284741Sdavidcs siz = auth_len; 720284741Sdavidcs while (siz > 0) { 721284741Sdavidcs if (M_TRAILINGSPACE(mb) == 0) { 722284741Sdavidcs MGET(mb2, M_WAIT, MT_DATA); 723284741Sdavidcs if (siz >= MINCLSIZE) 724284741Sdavidcs MCLGET(mb2, M_WAIT); 725284741Sdavidcs mb->m_next = mb2; 726284741Sdavidcs mb = mb2; 727284741Sdavidcs mb->m_len = 0; 728284741Sdavidcs bpos = mtod(mb, caddr_t); 729284741Sdavidcs } 730284741Sdavidcs i = min(siz, M_TRAILINGSPACE(mb)); 731284741Sdavidcs bcopy(auth_str, bpos, i); 732284741Sdavidcs mb->m_len += i; 733284741Sdavidcs auth_str += i; 734284741Sdavidcs bpos += i; 735284741Sdavidcs siz -= i; 736284741Sdavidcs } 737284741Sdavidcs if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 738284741Sdavidcs for (i = 0; i < siz; i++) 739284741Sdavidcs *bpos++ = '\0'; 740284741Sdavidcs mb->m_len += siz; 741284741Sdavidcs } 742284741Sdavidcs break; 743284741Sdavidcs }; 744284741Sdavidcs 745284741Sdavidcs /* 746284741Sdavidcs * And the verifier... 747284741Sdavidcs */ 748284741Sdavidcs nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 749284741Sdavidcs if (verf_str) { 750284741Sdavidcs *tl++ = txdr_unsigned(RPCAUTH_KERB4); 751284741Sdavidcs *tl = txdr_unsigned(verf_len); 752284741Sdavidcs siz = verf_len; 753284741Sdavidcs while (siz > 0) { 754284741Sdavidcs if (M_TRAILINGSPACE(mb) == 0) { 755284741Sdavidcs MGET(mb2, M_WAIT, MT_DATA); 756284741Sdavidcs if (siz >= MINCLSIZE) 757284741Sdavidcs MCLGET(mb2, M_WAIT); 758284741Sdavidcs mb->m_next = mb2; 759284741Sdavidcs mb = mb2; 760284741Sdavidcs mb->m_len = 0; 761284741Sdavidcs bpos = mtod(mb, caddr_t); 762284741Sdavidcs } 763284741Sdavidcs i = min(siz, M_TRAILINGSPACE(mb)); 764284741Sdavidcs bcopy(verf_str, bpos, i); 765284741Sdavidcs mb->m_len += i; 766284741Sdavidcs verf_str += i; 767284741Sdavidcs bpos += i; 768284741Sdavidcs siz -= i; 769284741Sdavidcs } 770284741Sdavidcs if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 771284741Sdavidcs for (i = 0; i < siz; i++) 772284741Sdavidcs *bpos++ = '\0'; 773284741Sdavidcs mb->m_len += siz; 774284741Sdavidcs } 775284741Sdavidcs } else { 776284741Sdavidcs *tl++ = txdr_unsigned(RPCAUTH_NULL); 777284741Sdavidcs *tl = 0; 778284741Sdavidcs } 779284741Sdavidcs mb->m_next = mrest; 780284741Sdavidcs mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 781284741Sdavidcs mreq->m_pkthdr.rcvif = (struct ifnet *)0; 782284741Sdavidcs *mbp = mb; 783284741Sdavidcs return (mreq); 784284741Sdavidcs} 785284741Sdavidcs 786284741Sdavidcs/* 787284741Sdavidcs * copies mbuf chain to the uio scatter/gather list 788284741Sdavidcs */ 789284741Sdavidcsint 790284741Sdavidcsnfsm_mbuftouio(mrep, uiop, siz, dpos) 791284741Sdavidcs struct mbuf **mrep; 792284741Sdavidcs register struct uio *uiop; 793284741Sdavidcs int siz; 794284741Sdavidcs caddr_t *dpos; 795284741Sdavidcs{ 796284741Sdavidcs register char *mbufcp, *uiocp; 797284741Sdavidcs register int xfer, left, len; 798284741Sdavidcs register struct mbuf *mp; 799284741Sdavidcs long uiosiz, rem; 800284741Sdavidcs int error = 0; 801284741Sdavidcs 802284741Sdavidcs mp = *mrep; 803284741Sdavidcs mbufcp = *dpos; 804284741Sdavidcs len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 805284741Sdavidcs rem = nfsm_rndup(siz)-siz; 806284741Sdavidcs while (siz > 0) { 807284741Sdavidcs if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 808284741Sdavidcs return (EFBIG); 809284741Sdavidcs left = uiop->uio_iov->iov_len; 810284741Sdavidcs uiocp = uiop->uio_iov->iov_base; 811284741Sdavidcs if (left > siz) 812284741Sdavidcs left = siz; 813284741Sdavidcs uiosiz = left; 814284741Sdavidcs while (left > 0) { 815284741Sdavidcs while (len == 0) { 816284741Sdavidcs mp = mp->m_next; 817284741Sdavidcs if (mp == NULL) 818284741Sdavidcs return (EBADRPC); 819284741Sdavidcs mbufcp = mtod(mp, caddr_t); 820284741Sdavidcs len = mp->m_len; 821284741Sdavidcs } 822284741Sdavidcs xfer = (left > len) ? len : left; 823284741Sdavidcs#ifdef notdef 824284741Sdavidcs /* Not Yet.. */ 825284741Sdavidcs if (uiop->uio_iov->iov_op != NULL) 826284741Sdavidcs (*(uiop->uio_iov->iov_op)) 827284741Sdavidcs (mbufcp, uiocp, xfer); 828284741Sdavidcs else 829284741Sdavidcs#endif 830284741Sdavidcs if (uiop->uio_segflg == UIO_SYSSPACE) 831284741Sdavidcs bcopy(mbufcp, uiocp, xfer); 832284741Sdavidcs else 833284741Sdavidcs copyout(mbufcp, uiocp, xfer); 834284741Sdavidcs left -= xfer; 835284741Sdavidcs len -= xfer; 836284741Sdavidcs mbufcp += xfer; 837284741Sdavidcs uiocp += xfer; 838284741Sdavidcs uiop->uio_offset += xfer; 839284741Sdavidcs uiop->uio_resid -= xfer; 840284741Sdavidcs } 841284741Sdavidcs if (uiop->uio_iov->iov_len <= siz) { 842284741Sdavidcs uiop->uio_iovcnt--; 843284741Sdavidcs uiop->uio_iov++; 844284741Sdavidcs } else { 845284741Sdavidcs uiop->uio_iov->iov_base += uiosiz; 846284741Sdavidcs uiop->uio_iov->iov_len -= uiosiz; 847284741Sdavidcs } 848284741Sdavidcs siz -= uiosiz; 849284741Sdavidcs } 850284741Sdavidcs *dpos = mbufcp; 851284741Sdavidcs *mrep = mp; 852284741Sdavidcs if (rem > 0) { 853284741Sdavidcs if (len < rem) 854284741Sdavidcs error = nfs_adv(mrep, dpos, rem, len); 855284741Sdavidcs else 856284741Sdavidcs *dpos += rem; 857284741Sdavidcs } 858284741Sdavidcs return (error); 859284741Sdavidcs} 860284741Sdavidcs 861284741Sdavidcs/* 862284741Sdavidcs * copies a uio scatter/gather list to an mbuf chain. 863284741Sdavidcs * NOTE: can ony handle iovcnt == 1 864284741Sdavidcs */ 865284741Sdavidcsint 866284741Sdavidcsnfsm_uiotombuf(uiop, mq, siz, bpos) 867284741Sdavidcs register struct uio *uiop; 868284741Sdavidcs struct mbuf **mq; 869284741Sdavidcs int siz; 870284741Sdavidcs caddr_t *bpos; 871284741Sdavidcs{ 872284741Sdavidcs register char *uiocp; 873284741Sdavidcs register struct mbuf *mp, *mp2; 874284741Sdavidcs register int xfer, left, mlen; 875284741Sdavidcs int uiosiz, clflg, rem; 876284741Sdavidcs char *cp; 877284741Sdavidcs 878284741Sdavidcs#ifdef DIAGNOSTIC 879284741Sdavidcs if (uiop->uio_iovcnt != 1) 880284741Sdavidcs panic("nfsm_uiotombuf: iovcnt != 1"); 881284741Sdavidcs#endif 882284741Sdavidcs 883284741Sdavidcs if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 884284741Sdavidcs clflg = 1; 885284741Sdavidcs else 886284741Sdavidcs clflg = 0; 887284741Sdavidcs rem = nfsm_rndup(siz)-siz; 888284741Sdavidcs mp = mp2 = *mq; 889284741Sdavidcs while (siz > 0) { 890284741Sdavidcs left = uiop->uio_iov->iov_len; 891284741Sdavidcs uiocp = uiop->uio_iov->iov_base; 892284741Sdavidcs if (left > siz) 893284741Sdavidcs left = siz; 894284741Sdavidcs uiosiz = left; 895284741Sdavidcs while (left > 0) { 896284741Sdavidcs mlen = M_TRAILINGSPACE(mp); 897284741Sdavidcs if (mlen == 0) { 898284741Sdavidcs MGET(mp, M_WAIT, MT_DATA); 899284741Sdavidcs if (clflg) 900284741Sdavidcs MCLGET(mp, M_WAIT); 901284741Sdavidcs mp->m_len = 0; 902284741Sdavidcs mp2->m_next = mp; 903284741Sdavidcs mp2 = mp; 904284741Sdavidcs mlen = M_TRAILINGSPACE(mp); 905284741Sdavidcs } 906284741Sdavidcs xfer = (left > mlen) ? mlen : left; 907284741Sdavidcs#ifdef notdef 908284741Sdavidcs /* Not Yet.. */ 909284741Sdavidcs if (uiop->uio_iov->iov_op != NULL) 910284741Sdavidcs (*(uiop->uio_iov->iov_op)) 911284741Sdavidcs (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 912284741Sdavidcs else 913284741Sdavidcs#endif 914284741Sdavidcs if (uiop->uio_segflg == UIO_SYSSPACE) 915284741Sdavidcs bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 916284741Sdavidcs else 917284741Sdavidcs copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 918284741Sdavidcs mp->m_len += xfer; 919284741Sdavidcs left -= xfer; 920284741Sdavidcs uiocp += xfer; 921284741Sdavidcs uiop->uio_offset += xfer; 922284741Sdavidcs uiop->uio_resid -= xfer; 923284741Sdavidcs } 924284741Sdavidcs uiop->uio_iov->iov_base += uiosiz; 925284741Sdavidcs uiop->uio_iov->iov_len -= uiosiz; 926284741Sdavidcs siz -= uiosiz; 927284741Sdavidcs } 928284741Sdavidcs if (rem > 0) { 929284741Sdavidcs if (rem > M_TRAILINGSPACE(mp)) { 930284741Sdavidcs MGET(mp, M_WAIT, MT_DATA); 931284741Sdavidcs mp->m_len = 0; 932284741Sdavidcs mp2->m_next = mp; 933284741Sdavidcs } 934284741Sdavidcs cp = mtod(mp, caddr_t)+mp->m_len; 935284741Sdavidcs for (left = 0; left < rem; left++) 936284741Sdavidcs *cp++ = '\0'; 937284741Sdavidcs mp->m_len += rem; 938284741Sdavidcs *bpos = cp; 939284741Sdavidcs } else 940284741Sdavidcs *bpos = mtod(mp, caddr_t)+mp->m_len; 941284741Sdavidcs *mq = mp; 942284741Sdavidcs return (0); 943284741Sdavidcs} 944284741Sdavidcs 945284741Sdavidcs/* 946284741Sdavidcs * Help break down an mbuf chain by setting the first siz bytes contiguous 947284741Sdavidcs * pointed to by returned val. 948284741Sdavidcs * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 949284741Sdavidcs * cases. (The macros use the vars. dpos and dpos2) 950284741Sdavidcs */ 951284741Sdavidcsint 952284741Sdavidcsnfsm_disct(mdp, dposp, siz, left, cp2) 953284741Sdavidcs struct mbuf **mdp; 954284741Sdavidcs caddr_t *dposp; 955284741Sdavidcs int siz; 956284741Sdavidcs int left; 957284741Sdavidcs caddr_t *cp2; 958284741Sdavidcs{ 959284741Sdavidcs register struct mbuf *mp, *mp2; 960284741Sdavidcs register int siz2, xfer; 961284741Sdavidcs register caddr_t p; 962284741Sdavidcs 963284741Sdavidcs mp = *mdp; 964284741Sdavidcs while (left == 0) { 965284741Sdavidcs *mdp = mp = mp->m_next; 966284741Sdavidcs if (mp == NULL) 967284741Sdavidcs return (EBADRPC); 968284741Sdavidcs left = mp->m_len; 969284741Sdavidcs *dposp = mtod(mp, caddr_t); 970284741Sdavidcs } 971284741Sdavidcs if (left >= siz) { 972284741Sdavidcs *cp2 = *dposp; 973284741Sdavidcs *dposp += siz; 974284741Sdavidcs } else if (mp->m_next == NULL) { 975284741Sdavidcs return (EBADRPC); 976284741Sdavidcs } else if (siz > MHLEN) { 977284741Sdavidcs panic("nfs S too big"); 978284741Sdavidcs } else { 979284741Sdavidcs MGET(mp2, M_WAIT, MT_DATA); 980284741Sdavidcs mp2->m_next = mp->m_next; 981284741Sdavidcs mp->m_next = mp2; 982284741Sdavidcs mp->m_len -= left; 983284741Sdavidcs mp = mp2; 984284741Sdavidcs *cp2 = p = mtod(mp, caddr_t); 985284741Sdavidcs bcopy(*dposp, p, left); /* Copy what was left */ 986284741Sdavidcs siz2 = siz-left; 987284741Sdavidcs p += left; 988284741Sdavidcs mp2 = mp->m_next; 989284741Sdavidcs /* Loop around copying up the siz2 bytes */ 990284741Sdavidcs while (siz2 > 0) { 991284741Sdavidcs if (mp2 == NULL) 992284741Sdavidcs return (EBADRPC); 993284741Sdavidcs xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 994284741Sdavidcs if (xfer > 0) { 995284741Sdavidcs bcopy(mtod(mp2, caddr_t), p, xfer); 996284741Sdavidcs NFSMADV(mp2, xfer); 997284741Sdavidcs mp2->m_len -= xfer; 998284741Sdavidcs p += xfer; 999284741Sdavidcs siz2 -= xfer; 1000284741Sdavidcs } 1001284741Sdavidcs if (siz2 > 0) 1002284741Sdavidcs mp2 = mp2->m_next; 1003284741Sdavidcs } 1004284741Sdavidcs mp->m_len = siz; 1005284741Sdavidcs *mdp = mp2; 1006284741Sdavidcs *dposp = mtod(mp2, caddr_t); 1007284741Sdavidcs } 1008284741Sdavidcs return (0); 1009284741Sdavidcs} 1010284741Sdavidcs 1011284741Sdavidcs/* 1012284741Sdavidcs * Advance the position in the mbuf chain. 1013284741Sdavidcs */ 1014284741Sdavidcsint 1015284741Sdavidcsnfs_adv(mdp, dposp, offs, left) 1016284741Sdavidcs struct mbuf **mdp; 1017284741Sdavidcs caddr_t *dposp; 1018284741Sdavidcs int offs; 1019284741Sdavidcs int left; 1020284741Sdavidcs{ 1021284741Sdavidcs register struct mbuf *m; 1022284741Sdavidcs register int s; 1023284741Sdavidcs 1024284741Sdavidcs m = *mdp; 1025284741Sdavidcs s = left; 1026284741Sdavidcs while (s < offs) { 1027284741Sdavidcs offs -= s; 1028284741Sdavidcs m = m->m_next; 1029284741Sdavidcs if (m == NULL) 1030284741Sdavidcs return (EBADRPC); 1031284741Sdavidcs s = m->m_len; 1032284741Sdavidcs } 1033284741Sdavidcs *mdp = m; 1034284741Sdavidcs *dposp = mtod(m, caddr_t)+offs; 1035284741Sdavidcs return (0); 1036284741Sdavidcs} 1037284741Sdavidcs 1038284741Sdavidcs/* 1039284741Sdavidcs * Copy a string into mbufs for the hard cases... 1040284741Sdavidcs */ 1041284741Sdavidcsint 1042284741Sdavidcsnfsm_strtmbuf(mb, bpos, cp, siz) 1043284741Sdavidcs struct mbuf **mb; 1044284741Sdavidcs char **bpos; 1045284741Sdavidcs const char *cp; 1046284741Sdavidcs long siz; 1047284741Sdavidcs{ 1048284741Sdavidcs register struct mbuf *m1 = NULL, *m2; 1049284741Sdavidcs long left, xfer, len, tlen; 1050284741Sdavidcs u_int32_t *tl; 1051284741Sdavidcs int putsize; 1052284741Sdavidcs 1053284741Sdavidcs putsize = 1; 1054284741Sdavidcs m2 = *mb; 1055284741Sdavidcs left = M_TRAILINGSPACE(m2); 1056284741Sdavidcs if (left > 0) { 1057284741Sdavidcs tl = ((u_int32_t *)(*bpos)); 1058284741Sdavidcs *tl++ = txdr_unsigned(siz); 1059284741Sdavidcs putsize = 0; 1060284741Sdavidcs left -= NFSX_UNSIGNED; 1061284741Sdavidcs m2->m_len += NFSX_UNSIGNED; 1062284741Sdavidcs if (left > 0) { 1063284741Sdavidcs bcopy(cp, (caddr_t) tl, left); 1064284741Sdavidcs siz -= left; 1065284741Sdavidcs cp += left; 1066284741Sdavidcs m2->m_len += left; 1067284741Sdavidcs left = 0; 1068284741Sdavidcs } 1069284741Sdavidcs } 1070284741Sdavidcs /* Loop around adding mbufs */ 1071284741Sdavidcs while (siz > 0) { 1072284741Sdavidcs MGET(m1, M_WAIT, MT_DATA); 1073284741Sdavidcs if (siz > MLEN) 1074284741Sdavidcs MCLGET(m1, M_WAIT); 1075284741Sdavidcs m1->m_len = NFSMSIZ(m1); 1076284741Sdavidcs m2->m_next = m1; 1077284741Sdavidcs m2 = m1; 1078284741Sdavidcs tl = mtod(m1, u_int32_t *); 1079284741Sdavidcs tlen = 0; 1080284741Sdavidcs if (putsize) { 1081284741Sdavidcs *tl++ = txdr_unsigned(siz); 1082284741Sdavidcs m1->m_len -= NFSX_UNSIGNED; 1083284741Sdavidcs tlen = NFSX_UNSIGNED; 1084284741Sdavidcs putsize = 0; 1085284741Sdavidcs } 1086284741Sdavidcs if (siz < m1->m_len) { 1087284741Sdavidcs len = nfsm_rndup(siz); 1088284741Sdavidcs xfer = siz; 1089284741Sdavidcs if (xfer < len) 1090284741Sdavidcs *(tl+(xfer>>2)) = 0; 1091284741Sdavidcs } else { 1092284741Sdavidcs xfer = len = m1->m_len; 1093284741Sdavidcs } 1094284741Sdavidcs bcopy(cp, (caddr_t) tl, xfer); 1095284741Sdavidcs m1->m_len = len+tlen; 1096284741Sdavidcs siz -= xfer; 1097284741Sdavidcs cp += xfer; 1098284741Sdavidcs } 1099284741Sdavidcs *mb = m1; 1100284741Sdavidcs *bpos = mtod(m1, caddr_t)+m1->m_len; 1101284741Sdavidcs return (0); 1102284741Sdavidcs} 1103284741Sdavidcs 1104284741Sdavidcs/* 1105284741Sdavidcs * Called once to initialize data structures... 1106284741Sdavidcs */ 1107284741Sdavidcsint 1108284741Sdavidcsnfs_init(vfsp) 1109284741Sdavidcs struct vfsconf *vfsp; 1110284741Sdavidcs{ 1111284741Sdavidcs register int i; 1112284741Sdavidcs 1113284741Sdavidcs nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 1114284741Sdavidcs 1115284741Sdavidcs /* 1116284741Sdavidcs * Check to see if major data structures haven't bloated. 1117284741Sdavidcs */ 1118284741Sdavidcs if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 1119284741Sdavidcs printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 1120284741Sdavidcs printf("Try reducing NFS_UIDHASHSIZ\n"); 1121284741Sdavidcs } 1122284741Sdavidcs if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 1123284741Sdavidcs printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 1124284741Sdavidcs printf("Try unionizing the nu_nickname and nu_flag fields\n"); 1125284741Sdavidcs } 1126284741Sdavidcs nfs_mount_type = vfsp->vfc_typenum; 1127284741Sdavidcs nfsrtt.pos = 0; 1128284741Sdavidcs rpc_vers = txdr_unsigned(RPC_VER2); 1129284741Sdavidcs rpc_call = txdr_unsigned(RPC_CALL); 1130284741Sdavidcs rpc_reply = txdr_unsigned(RPC_REPLY); 1131284741Sdavidcs rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 1132284741Sdavidcs rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 1133284741Sdavidcs rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 1134284741Sdavidcs rpc_autherr = txdr_unsigned(RPC_AUTHERR); 1135284741Sdavidcs rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1136284741Sdavidcs rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 1137284741Sdavidcs nfs_prog = txdr_unsigned(NFS_PROG); 1138284741Sdavidcs nqnfs_prog = txdr_unsigned(NQNFS_PROG); 1139284741Sdavidcs nfs_true = txdr_unsigned(TRUE); 1140284741Sdavidcs nfs_false = txdr_unsigned(FALSE); 1141284741Sdavidcs nfs_xdrneg1 = txdr_unsigned(-1); 1142284741Sdavidcs nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1143284741Sdavidcs if (nfs_ticks < 1) 1144284741Sdavidcs nfs_ticks = 1; 1145284741Sdavidcs /* Ensure async daemons disabled */ 1146284741Sdavidcs for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 1147284741Sdavidcs nfs_iodwant[i] = (struct proc *)0; 1148284741Sdavidcs nfs_iodmount[i] = (struct nfsmount *)0; 1149284741Sdavidcs } 1150284741Sdavidcs nfs_nhinit(); /* Init the nfsnode table */ 1151284741Sdavidcs#ifndef NFS_NOSERVER 1152284741Sdavidcs nfsrv_init(0); /* Init server data structures */ 1153284741Sdavidcs nfsrv_initcache(); /* Init the server request cache */ 1154284741Sdavidcs#endif 1155284741Sdavidcs 1156284741Sdavidcs /* 1157284741Sdavidcs * Initialize the nqnfs server stuff. 1158284741Sdavidcs */ 1159284741Sdavidcs if (nqnfsstarttime == 0) { 1160284741Sdavidcs nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 1161284741Sdavidcs + nqsrv_clockskew + nqsrv_writeslack; 1162284741Sdavidcs NQLOADNOVRAM(nqnfsstarttime); 1163284741Sdavidcs CIRCLEQ_INIT(&nqtimerhead); 1164284741Sdavidcs nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 1165284741Sdavidcs } 1166284741Sdavidcs 1167284741Sdavidcs /* 1168284741Sdavidcs * Initialize reply list and start timer 1169284741Sdavidcs */ 1170284741Sdavidcs TAILQ_INIT(&nfs_reqq); 1171284741Sdavidcs 1172284741Sdavidcs nfs_timer(0); 1173284741Sdavidcs 1174284741Sdavidcs /* 1175284741Sdavidcs * Set up lease_check and lease_updatetime so that other parts 1176284741Sdavidcs * of the system can call us, if we are loadable. 1177284741Sdavidcs */ 1178284741Sdavidcs#ifndef NFS_NOSERVER 1179284741Sdavidcs nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; 1180284741Sdavidcs default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; 1181284741Sdavidcs#endif 1182284741Sdavidcs nfs_prev_lease_updatetime = lease_updatetime; 1183284741Sdavidcs lease_updatetime = nfs_lease_updatetime; 1184284741Sdavidcs nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 1185284741Sdavidcs sysent[SYS_nfssvc].sy_narg = 2; 1186284741Sdavidcs nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 1187284741Sdavidcs sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 1188284741Sdavidcs#ifndef NFS_NOSERVER 1189284741Sdavidcs nfs_prev_getfh_sy_narg = sysent[SYS_getfh].sy_narg; 1190284741Sdavidcs sysent[SYS_getfh].sy_narg = 2; 1191284741Sdavidcs nfs_prev_getfh_sy_call = sysent[SYS_getfh].sy_call; 1192284741Sdavidcs sysent[SYS_getfh].sy_call = (sy_call_t *)getfh; 1193284741Sdavidcs#endif 1194284741Sdavidcs 1195284741Sdavidcs nfs_pbuf_freecnt = nswbuf / 2 + 1; 1196284741Sdavidcs 1197284741Sdavidcs return (0); 1198284741Sdavidcs} 1199284741Sdavidcs 1200284741Sdavidcsint 1201284741Sdavidcsnfs_uninit(vfsp) 1202284741Sdavidcs struct vfsconf *vfsp; 1203284741Sdavidcs{ 1204284741Sdavidcs 1205284741Sdavidcs untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 1206284741Sdavidcs nfs_mount_type = -1; 1207284741Sdavidcs#ifndef NFS_NOSERVER 1208284741Sdavidcs default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; 1209284741Sdavidcs#endif 1210284741Sdavidcs lease_updatetime = nfs_prev_lease_updatetime; 1211284741Sdavidcs sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 1212284741Sdavidcs sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 1213284741Sdavidcs#ifndef NFS_NOSERVER 1214284741Sdavidcs sysent[SYS_getfh].sy_narg = nfs_prev_getfh_sy_narg; 1215284741Sdavidcs sysent[SYS_getfh].sy_call = nfs_prev_getfh_sy_call; 1216284741Sdavidcs#endif 1217284741Sdavidcs return (0); 1218284741Sdavidcs} 1219284741Sdavidcs 1220284741Sdavidcs/* 1221284741Sdavidcs * Attribute cache routines. 1222284741Sdavidcs * nfs_loadattrcache() - loads or updates the cache contents from attributes 1223284741Sdavidcs * that are on the mbuf list 1224284741Sdavidcs * nfs_getattrcache() - returns valid attributes if found in cache, returns 1225284741Sdavidcs * error otherwise 1226284741Sdavidcs */ 1227284741Sdavidcs 1228284741Sdavidcs/* 1229284741Sdavidcs * Load the attribute cache (that lives in the nfsnode entry) with 1230284741Sdavidcs * the values on the mbuf list and 1231284741Sdavidcs * Iff vap not NULL 1232284741Sdavidcs * copy the attributes to *vaper 1233284741Sdavidcs */ 1234284741Sdavidcsint 1235284741Sdavidcsnfs_loadattrcache(vpp, mdp, dposp, vaper) 1236284741Sdavidcs struct vnode **vpp; 1237284741Sdavidcs struct mbuf **mdp; 1238284741Sdavidcs caddr_t *dposp; 1239284741Sdavidcs struct vattr *vaper; 1240284741Sdavidcs{ 1241284741Sdavidcs register struct vnode *vp = *vpp; 1242284741Sdavidcs register struct vattr *vap; 1243284741Sdavidcs register struct nfs_fattr *fp; 1244284741Sdavidcs register struct nfsnode *np; 1245284741Sdavidcs register int32_t t1; 1246284741Sdavidcs caddr_t cp2; 1247284741Sdavidcs int error = 0, rdev; 1248284741Sdavidcs struct mbuf *md; 1249284741Sdavidcs enum vtype vtyp; 1250284741Sdavidcs u_short vmode; 1251284741Sdavidcs struct timespec mtime; 1252284741Sdavidcs struct vnode *nvp; 1253284741Sdavidcs int v3 = NFS_ISV3(vp); 1254284741Sdavidcs 1255284741Sdavidcs md = *mdp; 1256284741Sdavidcs t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1257284741Sdavidcs if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) 1258284741Sdavidcs return (error); 1259284741Sdavidcs fp = (struct nfs_fattr *)cp2; 1260284741Sdavidcs if (v3) { 1261284741Sdavidcs vtyp = nfsv3tov_type(fp->fa_type); 1262284741Sdavidcs vmode = fxdr_unsigned(u_short, fp->fa_mode); 1263284741Sdavidcs rdev = umakedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 1264284741Sdavidcs fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 1265284741Sdavidcs fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1266284741Sdavidcs } else { 1267284741Sdavidcs vtyp = nfsv2tov_type(fp->fa_type); 1268284741Sdavidcs vmode = fxdr_unsigned(u_short, fp->fa_mode); 1269284741Sdavidcs /* 1270284741Sdavidcs * XXX 1271284741Sdavidcs * 1272284741Sdavidcs * The duplicate information returned in fa_type and fa_mode 1273284741Sdavidcs * is an ambiguity in the NFS version 2 protocol. 1274284741Sdavidcs * 1275284741Sdavidcs * VREG should be taken literally as a regular file. If a 1276284741Sdavidcs * server intents to return some type information differently 1277284741Sdavidcs * in the upper bits of the mode field (e.g. for sockets, or 1278284741Sdavidcs * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 1279284741Sdavidcs * leave the examination of the mode bits even in the VREG 1280284741Sdavidcs * case to avoid breakage for bogus servers, but we make sure 1281284741Sdavidcs * that there are actually type bits set in the upper part of 1282284741Sdavidcs * fa_mode (and failing that, trust the va_type field). 1283284741Sdavidcs * 1284284741Sdavidcs * NFSv3 cleared the issue, and requires fa_mode to not 1285284741Sdavidcs * contain any type information (while also introduing sockets 1286284741Sdavidcs * and FIFOs for fa_type). 1287284741Sdavidcs */ 1288284741Sdavidcs if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 1289284741Sdavidcs vtyp = IFTOVT(vmode); 1290284741Sdavidcs rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 1291284741Sdavidcs fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1292284741Sdavidcs 1293284741Sdavidcs /* 1294284741Sdavidcs * Really ugly NFSv2 kludge. 1295284741Sdavidcs */ 1296284741Sdavidcs if (vtyp == VCHR && rdev == 0xffffffff) 1297284741Sdavidcs vtyp = VFIFO; 1298284741Sdavidcs } 1299284741Sdavidcs 1300284741Sdavidcs /* 1301284741Sdavidcs * If v_type == VNON it is a new node, so fill in the v_type, 1302284741Sdavidcs * n_mtime fields. Check to see if it represents a special 1303284741Sdavidcs * device, and if so, check for a possible alias. Once the 1304284741Sdavidcs * correct vnode has been obtained, fill in the rest of the 1305284741Sdavidcs * information. 1306284741Sdavidcs */ 1307284741Sdavidcs np = VTONFS(vp); 1308284741Sdavidcs if (vp->v_type != vtyp) { 1309284741Sdavidcs vp->v_type = vtyp; 1310284741Sdavidcs if (vp->v_type == VFIFO) { 1311284741Sdavidcs vp->v_op = fifo_nfsv2nodeop_p; 1312284741Sdavidcs } 1313284741Sdavidcs if (vp->v_type == VCHR || vp->v_type == VBLK) { 1314284741Sdavidcs vp->v_op = spec_nfsv2nodeop_p; 1315284741Sdavidcs nvp = checkalias(vp, rdev, vp->v_mount); 1316284741Sdavidcs if (nvp) { 1317284741Sdavidcs /* 1318284741Sdavidcs * Discard unneeded vnode, but save its nfsnode. 1319284741Sdavidcs * Since the nfsnode does not have a lock, its 1320284741Sdavidcs * vnode lock has to be carried over. 1321284741Sdavidcs */ 1322284741Sdavidcs nvp->v_vnlock = vp->v_vnlock; 1323284741Sdavidcs vp->v_vnlock = NULL; 1324284741Sdavidcs nvp->v_data = vp->v_data; 1325284741Sdavidcs vp->v_data = NULL; 1326284741Sdavidcs vp->v_op = spec_vnodeop_p; 1327284741Sdavidcs vrele(vp); 1328284741Sdavidcs vgone(vp); 1329284741Sdavidcs /* 1330284741Sdavidcs * Reinitialize aliased node. 1331284741Sdavidcs */ 1332284741Sdavidcs np->n_vnode = nvp; 1333284741Sdavidcs *vpp = vp = nvp; 1334284741Sdavidcs } 1335284741Sdavidcs } 1336284741Sdavidcs np->n_mtime = mtime.tv_sec; 1337284741Sdavidcs } 1338284741Sdavidcs vap = &np->n_vattr; 1339284741Sdavidcs vap->va_type = vtyp; 1340284741Sdavidcs vap->va_mode = (vmode & 07777); 1341284741Sdavidcs vap->va_rdev = rdev; 1342284741Sdavidcs vap->va_mtime = mtime; 1343284741Sdavidcs vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1344284741Sdavidcs if (v3) { 1345284741Sdavidcs vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1346284741Sdavidcs vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1347284741Sdavidcs vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1348284741Sdavidcs vap->va_size = fxdr_hyper(&fp->fa3_size); 1349284741Sdavidcs vap->va_blocksize = NFS_FABLKSIZE; 1350284741Sdavidcs vap->va_bytes = fxdr_hyper(&fp->fa3_used); 1351284741Sdavidcs vap->va_fileid = fxdr_unsigned(int32_t, 1352284741Sdavidcs fp->fa3_fileid.nfsuquad[1]); 1353284741Sdavidcs fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1354284741Sdavidcs fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1355284741Sdavidcs vap->va_flags = 0; 1356284741Sdavidcs vap->va_filerev = 0; 1357284741Sdavidcs } else { 1358284741Sdavidcs vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1359284741Sdavidcs vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1360284741Sdavidcs vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1361284741Sdavidcs vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1362284741Sdavidcs vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 1363284741Sdavidcs vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 1364284741Sdavidcs * NFS_FABLKSIZE; 1365284741Sdavidcs vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1366284741Sdavidcs fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1367284741Sdavidcs vap->va_flags = 0; 1368284741Sdavidcs vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 1369284741Sdavidcs fp->fa2_ctime.nfsv2_sec); 1370284741Sdavidcs vap->va_ctime.tv_nsec = 0; 1371284741Sdavidcs vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 1372284741Sdavidcs vap->va_filerev = 0; 1373284741Sdavidcs } 1374284741Sdavidcs if (vap->va_size != np->n_size) { 1375284741Sdavidcs if (vap->va_type == VREG) { 1376284741Sdavidcs if (np->n_flag & NMODIFIED) { 1377284741Sdavidcs if (vap->va_size < np->n_size) 1378284741Sdavidcs vap->va_size = np->n_size; 1379284741Sdavidcs else 1380284741Sdavidcs np->n_size = vap->va_size; 1381284741Sdavidcs } else 1382284741Sdavidcs np->n_size = vap->va_size; 1383284741Sdavidcs vnode_pager_setsize(vp, np->n_size); 1384284741Sdavidcs } else 1385284741Sdavidcs np->n_size = vap->va_size; 1386284741Sdavidcs } 1387284741Sdavidcs np->n_attrstamp = time_second; 1388284741Sdavidcs if (vaper != NULL) { 1389284741Sdavidcs bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 1390284741Sdavidcs if (np->n_flag & NCHG) { 1391284741Sdavidcs if (np->n_flag & NACC) 1392284741Sdavidcs vaper->va_atime = np->n_atim; 1393284741Sdavidcs if (np->n_flag & NUPD) 1394284741Sdavidcs vaper->va_mtime = np->n_mtim; 1395284741Sdavidcs } 1396284741Sdavidcs } 1397284741Sdavidcs return (0); 1398284741Sdavidcs} 1399284741Sdavidcs 1400284741Sdavidcs#ifdef NFS_ACDEBUG 1401284741Sdavidcs#include <sys/sysctl.h> 1402284741SdavidcsSYSCTL_DECL(_vfs_nfs); 1403284741Sdavidcsstatic int nfs_acdebug; 1404284741SdavidcsSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 1405284741Sdavidcs#endif 1406284741Sdavidcs 1407284741Sdavidcs/* 1408284741Sdavidcs * Check the time stamp 1409284741Sdavidcs * If the cache is valid, copy contents to *vap and return 0 1410284741Sdavidcs * otherwise return an error 1411284741Sdavidcs */ 1412284741Sdavidcsint 1413284741Sdavidcsnfs_getattrcache(vp, vaper) 1414284741Sdavidcs register struct vnode *vp; 1415284741Sdavidcs struct vattr *vaper; 1416284741Sdavidcs{ 1417284741Sdavidcs register struct nfsnode *np; 1418284741Sdavidcs register struct vattr *vap; 1419284741Sdavidcs struct nfsmount *nmp; 1420284741Sdavidcs int timeo; 1421284741Sdavidcs 1422284741Sdavidcs np = VTONFS(vp); 1423284741Sdavidcs vap = &np->n_vattr; 1424284741Sdavidcs nmp = VFSTONFS(vp->v_mount); 1425284741Sdavidcs /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 1426284741Sdavidcs timeo = (time_second - np->n_mtime) / 10; 1427284741Sdavidcs 1428284741Sdavidcs#ifdef NFS_ACDEBUG 1429284741Sdavidcs if (nfs_acdebug>1) 1430284741Sdavidcs printf("nfs_getattrcache: initial timeo = %d\n", timeo); 1431284741Sdavidcs#endif 1432284741Sdavidcs 1433284741Sdavidcs if (vap->va_type == VDIR) { 1434284741Sdavidcs if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 1435284741Sdavidcs timeo = nmp->nm_acdirmin; 1436284741Sdavidcs else if (timeo > nmp->nm_acdirmax) 1437284741Sdavidcs timeo = nmp->nm_acdirmax; 1438284741Sdavidcs } else { 1439284741Sdavidcs if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 1440284741Sdavidcs timeo = nmp->nm_acregmin; 1441284741Sdavidcs else if (timeo > nmp->nm_acregmax) 1442284741Sdavidcs timeo = nmp->nm_acregmax; 1443284741Sdavidcs } 1444284741Sdavidcs 1445284741Sdavidcs#ifdef NFS_ACDEBUG 1446284741Sdavidcs if (nfs_acdebug > 2) 1447284741Sdavidcs printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 1448284741Sdavidcs nmp->nm_acregmin, nmp->nm_acregmax, 1449284741Sdavidcs nmp->nm_acdirmin, nmp->nm_acdirmax); 1450284741Sdavidcs 1451284741Sdavidcs if (nfs_acdebug) 1452284741Sdavidcs printf("nfs_getattrcache: age = %d; final timeo = %d\n", 1453284741Sdavidcs (time_second - np->n_attrstamp), timeo); 1454284741Sdavidcs#endif 1455284741Sdavidcs 1456284741Sdavidcs if ((time_second - np->n_attrstamp) >= timeo) { 1457284741Sdavidcs nfsstats.attrcache_misses++; 1458284741Sdavidcs return (ENOENT); 1459284741Sdavidcs } 1460284741Sdavidcs nfsstats.attrcache_hits++; 1461284741Sdavidcs if (vap->va_size != np->n_size) { 1462284741Sdavidcs if (vap->va_type == VREG) { 1463284741Sdavidcs if (np->n_flag & NMODIFIED) { 1464284741Sdavidcs if (vap->va_size < np->n_size) 1465284741Sdavidcs vap->va_size = np->n_size; 1466284741Sdavidcs else 1467284741Sdavidcs np->n_size = vap->va_size; 1468284741Sdavidcs } else 1469284741Sdavidcs np->n_size = vap->va_size; 1470284741Sdavidcs vnode_pager_setsize(vp, np->n_size); 1471284741Sdavidcs } else 1472284741Sdavidcs np->n_size = vap->va_size; 1473284741Sdavidcs } 1474284741Sdavidcs bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 1475284741Sdavidcs if (np->n_flag & NCHG) { 1476284741Sdavidcs if (np->n_flag & NACC) 1477284741Sdavidcs vaper->va_atime = np->n_atim; 1478284741Sdavidcs if (np->n_flag & NUPD) 1479284741Sdavidcs vaper->va_mtime = np->n_mtim; 1480284741Sdavidcs } 1481284741Sdavidcs return (0); 1482284741Sdavidcs} 1483284741Sdavidcs 1484284741Sdavidcs#ifndef NFS_NOSERVER 1485284741Sdavidcs/* 1486284741Sdavidcs * Set up nameidata for a lookup() call and do it. 1487284741Sdavidcs * 1488284741Sdavidcs * If pubflag is set, this call is done for a lookup operation on the 1489284741Sdavidcs * public filehandle. In that case we allow crossing mountpoints and 1490284741Sdavidcs * absolute pathnames. However, the caller is expected to check that 1491284741Sdavidcs * the lookup result is within the public fs, and deny access if 1492284741Sdavidcs * it is not. 1493284741Sdavidcs * 1494284741Sdavidcs * nfs_namei() clears out garbage fields that namei() might leave garbage. 1495284741Sdavidcs * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 1496284741Sdavidcs * error occurs but the parent was not requested. 1497284741Sdavidcs * 1498284741Sdavidcs * dirp may be set whether an error is returned or not, and must be 1499284741Sdavidcs * released by the caller. 1500284741Sdavidcs */ 1501284741Sdavidcsint 1502284741Sdavidcsnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 1503284741Sdavidcs register struct nameidata *ndp; 1504284741Sdavidcs fhandle_t *fhp; 1505284741Sdavidcs int len; 1506284741Sdavidcs struct nfssvc_sock *slp; 1507284741Sdavidcs struct sockaddr *nam; 1508284741Sdavidcs struct mbuf **mdp; 1509284741Sdavidcs caddr_t *dposp; 1510284741Sdavidcs struct vnode **retdirp; 1511284741Sdavidcs struct proc *p; 1512284741Sdavidcs int kerbflag, pubflag; 1513284741Sdavidcs{ 1514284741Sdavidcs register int i, rem; 1515284741Sdavidcs register struct mbuf *md; 1516284741Sdavidcs register char *fromcp, *tocp, *cp; 1517284741Sdavidcs struct iovec aiov; 1518284741Sdavidcs struct uio auio; 1519284741Sdavidcs struct vnode *dp; 1520284741Sdavidcs int error, rdonly, linklen; 1521284741Sdavidcs struct componentname *cnp = &ndp->ni_cnd; 1522284741Sdavidcs 1523284741Sdavidcs *retdirp = (struct vnode *)0; 1524284741Sdavidcs cnp->cn_pnbuf = zalloc(namei_zone); 1525284741Sdavidcs 1526284741Sdavidcs /* 1527284741Sdavidcs * Copy the name from the mbuf list to ndp->ni_pnbuf 1528284741Sdavidcs * and set the various ndp fields appropriately. 1529284741Sdavidcs */ 1530284741Sdavidcs fromcp = *dposp; 1531284741Sdavidcs tocp = cnp->cn_pnbuf; 1532284741Sdavidcs md = *mdp; 1533284741Sdavidcs rem = mtod(md, caddr_t) + md->m_len - fromcp; 1534284741Sdavidcs cnp->cn_hash = 0; 1535284741Sdavidcs for (i = 0; i < len; i++) { 1536284741Sdavidcs while (rem == 0) { 1537284741Sdavidcs md = md->m_next; 1538284741Sdavidcs if (md == NULL) { 1539284741Sdavidcs error = EBADRPC; 1540284741Sdavidcs goto out; 1541284741Sdavidcs } 1542284741Sdavidcs fromcp = mtod(md, caddr_t); 1543284741Sdavidcs rem = md->m_len; 1544284741Sdavidcs } 1545284741Sdavidcs if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 1546284741Sdavidcs error = EACCES; 1547284741Sdavidcs goto out; 1548284741Sdavidcs } 1549284741Sdavidcs cnp->cn_hash += (unsigned char)*fromcp; 1550284741Sdavidcs *tocp++ = *fromcp++; 1551284741Sdavidcs rem--; 1552284741Sdavidcs } 1553284741Sdavidcs *tocp = '\0'; 1554284741Sdavidcs *mdp = md; 1555284741Sdavidcs *dposp = fromcp; 1556284741Sdavidcs len = nfsm_rndup(len)-len; 1557284741Sdavidcs if (len > 0) { 1558284741Sdavidcs if (rem >= len) 1559284741Sdavidcs *dposp += len; 1560284741Sdavidcs else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 1561284741Sdavidcs goto out; 1562284741Sdavidcs } 1563284741Sdavidcs 1564284741Sdavidcs /* 1565284741Sdavidcs * Extract and set starting directory. 1566284741Sdavidcs */ 1567284741Sdavidcs error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 1568284741Sdavidcs nam, &rdonly, kerbflag, pubflag); 1569284741Sdavidcs if (error) 1570284741Sdavidcs goto out; 1571284741Sdavidcs if (dp->v_type != VDIR) { 1572284741Sdavidcs vrele(dp); 1573284741Sdavidcs error = ENOTDIR; 1574284741Sdavidcs goto out; 1575284741Sdavidcs } 1576284741Sdavidcs 1577284741Sdavidcs if (rdonly) 1578284741Sdavidcs cnp->cn_flags |= RDONLY; 1579284741Sdavidcs 1580284741Sdavidcs /* 1581284741Sdavidcs * Set return directory. Reference to dp is implicitly transfered 1582284741Sdavidcs * to the returned pointer 1583284741Sdavidcs */ 1584284741Sdavidcs *retdirp = dp; 1585284741Sdavidcs 1586284741Sdavidcs if (pubflag) { 1587284741Sdavidcs /* 1588284741Sdavidcs * Oh joy. For WebNFS, handle those pesky '%' escapes, 1589284741Sdavidcs * and the 'native path' indicator. 1590284741Sdavidcs */ 1591284741Sdavidcs cp = zalloc(namei_zone); 1592284741Sdavidcs fromcp = cnp->cn_pnbuf; 1593284741Sdavidcs tocp = cp; 1594284741Sdavidcs if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 1595284741Sdavidcs switch ((unsigned char)*fromcp) { 1596284741Sdavidcs case WEBNFS_NATIVE_CHAR: 1597284741Sdavidcs /* 1598284741Sdavidcs * 'Native' path for us is the same 1599284741Sdavidcs * as a path according to the NFS spec, 1600284741Sdavidcs * just skip the escape char. 1601284741Sdavidcs */ 1602284741Sdavidcs fromcp++; 1603284741Sdavidcs break; 1604284741Sdavidcs /* 1605284741Sdavidcs * More may be added in the future, range 0x80-0xff 1606284741Sdavidcs */ 1607284741Sdavidcs default: 1608284741Sdavidcs error = EIO; 1609284741Sdavidcs zfree(namei_zone, cp); 1610284741Sdavidcs goto out; 1611284741Sdavidcs } 1612284741Sdavidcs } 1613284741Sdavidcs /* 1614284741Sdavidcs * Translate the '%' escapes, URL-style. 1615284741Sdavidcs */ 1616284741Sdavidcs while (*fromcp != '\0') { 1617284741Sdavidcs if (*fromcp == WEBNFS_ESC_CHAR) { 1618284741Sdavidcs if (fromcp[1] != '\0' && fromcp[2] != '\0') { 1619284741Sdavidcs fromcp++; 1620284741Sdavidcs *tocp++ = HEXSTRTOI(fromcp); 1621284741Sdavidcs fromcp += 2; 1622284741Sdavidcs continue; 1623284741Sdavidcs } else { 1624284741Sdavidcs error = ENOENT; 1625284741Sdavidcs zfree(namei_zone, cp); 1626284741Sdavidcs goto out; 1627284741Sdavidcs } 1628284741Sdavidcs } else 1629284741Sdavidcs *tocp++ = *fromcp++; 1630284741Sdavidcs } 1631284741Sdavidcs *tocp = '\0'; 1632284741Sdavidcs zfree(namei_zone, cnp->cn_pnbuf); 1633284741Sdavidcs cnp->cn_pnbuf = cp; 1634284741Sdavidcs } 1635284741Sdavidcs 1636284741Sdavidcs ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 1637284741Sdavidcs ndp->ni_segflg = UIO_SYSSPACE; 1638284741Sdavidcs 1639284741Sdavidcs if (pubflag) { 1640284741Sdavidcs ndp->ni_rootdir = rootvnode; 1641284741Sdavidcs ndp->ni_loopcnt = 0; 1642284741Sdavidcs if (cnp->cn_pnbuf[0] == '/') 1643284741Sdavidcs dp = rootvnode; 1644284741Sdavidcs } else { 1645284741Sdavidcs cnp->cn_flags |= NOCROSSMOUNT; 1646284741Sdavidcs } 1647284741Sdavidcs 1648284741Sdavidcs /* 1649284741Sdavidcs * Initialize for scan, set ni_startdir and bump ref on dp again 1650284741Sdavidcs * becuase lookup() will dereference ni_startdir. 1651284741Sdavidcs */ 1652284741Sdavidcs 1653284741Sdavidcs cnp->cn_proc = p; 1654284741Sdavidcs VREF(dp); 1655284741Sdavidcs ndp->ni_startdir = dp; 1656284741Sdavidcs 1657284741Sdavidcs for (;;) { 1658284741Sdavidcs cnp->cn_nameptr = cnp->cn_pnbuf; 1659284741Sdavidcs /* 1660284741Sdavidcs * Call lookup() to do the real work. If an error occurs, 1661284741Sdavidcs * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 1662284741Sdavidcs * we do not have to dereference anything before returning. 1663284741Sdavidcs * In either case ni_startdir will be dereferenced and NULLed 1664284741Sdavidcs * out. 1665284741Sdavidcs */ 1666284741Sdavidcs error = lookup(ndp); 1667284741Sdavidcs if (error) 1668284741Sdavidcs break; 1669284741Sdavidcs 1670284741Sdavidcs /* 1671284741Sdavidcs * Check for encountering a symbolic link. Trivial 1672284741Sdavidcs * termination occurs if no symlink encountered. 1673284741Sdavidcs * Note: zfree is safe because error is 0, so we will 1674284741Sdavidcs * not zfree it again when we break. 1675284741Sdavidcs */ 1676284741Sdavidcs if ((cnp->cn_flags & ISSYMLINK) == 0) { 1677284741Sdavidcs nfsrv_object_create(ndp->ni_vp); 1678284741Sdavidcs if (cnp->cn_flags & (SAVENAME | SAVESTART)) 1679284741Sdavidcs cnp->cn_flags |= HASBUF; 1680284741Sdavidcs else 1681284741Sdavidcs zfree(namei_zone, cnp->cn_pnbuf); 1682284741Sdavidcs break; 1683284741Sdavidcs } 1684284741Sdavidcs 1685284741Sdavidcs /* 1686284741Sdavidcs * Validate symlink 1687284741Sdavidcs */ 1688284741Sdavidcs if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1689284741Sdavidcs VOP_UNLOCK(ndp->ni_dvp, 0, p); 1690284741Sdavidcs if (!pubflag) { 1691284741Sdavidcs error = EINVAL; 1692284741Sdavidcs goto badlink2; 1693284741Sdavidcs } 1694284741Sdavidcs 1695284741Sdavidcs if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1696284741Sdavidcs error = ELOOP; 1697284741Sdavidcs goto badlink2; 1698284741Sdavidcs } 1699284741Sdavidcs if (ndp->ni_pathlen > 1) 1700284741Sdavidcs cp = zalloc(namei_zone); 1701284741Sdavidcs else 1702284741Sdavidcs cp = cnp->cn_pnbuf; 1703284741Sdavidcs aiov.iov_base = cp; 1704284741Sdavidcs aiov.iov_len = MAXPATHLEN; 1705284741Sdavidcs auio.uio_iov = &aiov; 1706284741Sdavidcs auio.uio_iovcnt = 1; 1707284741Sdavidcs auio.uio_offset = 0; 1708284741Sdavidcs auio.uio_rw = UIO_READ; 1709284741Sdavidcs auio.uio_segflg = UIO_SYSSPACE; 1710284741Sdavidcs auio.uio_procp = (struct proc *)0; 1711284741Sdavidcs auio.uio_resid = MAXPATHLEN; 1712284741Sdavidcs error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 1713284741Sdavidcs if (error) { 1714284741Sdavidcs badlink1: 1715284741Sdavidcs if (ndp->ni_pathlen > 1) 1716284741Sdavidcs zfree(namei_zone, cp); 1717284741Sdavidcs badlink2: 1718284741Sdavidcs vrele(ndp->ni_dvp); 1719284741Sdavidcs vput(ndp->ni_vp); 1720284741Sdavidcs break; 1721284741Sdavidcs } 1722284741Sdavidcs linklen = MAXPATHLEN - auio.uio_resid; 1723284741Sdavidcs if (linklen == 0) { 1724284741Sdavidcs error = ENOENT; 1725284741Sdavidcs goto badlink1; 1726284741Sdavidcs } 1727284741Sdavidcs if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 1728284741Sdavidcs error = ENAMETOOLONG; 1729284741Sdavidcs goto badlink1; 1730284741Sdavidcs } 1731284741Sdavidcs 1732284741Sdavidcs /* 1733284741Sdavidcs * Adjust or replace path 1734284741Sdavidcs */ 1735284741Sdavidcs if (ndp->ni_pathlen > 1) { 1736284741Sdavidcs bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 1737284741Sdavidcs zfree(namei_zone, cnp->cn_pnbuf); 1738284741Sdavidcs cnp->cn_pnbuf = cp; 1739284741Sdavidcs } else 1740284741Sdavidcs cnp->cn_pnbuf[linklen] = '\0'; 1741284741Sdavidcs ndp->ni_pathlen += linklen; 1742284741Sdavidcs 1743284741Sdavidcs /* 1744284741Sdavidcs * Cleanup refs for next loop and check if root directory 1745284741Sdavidcs * should replace current directory. Normally ni_dvp 1746284741Sdavidcs * becomes the new base directory and is cleaned up when 1747284741Sdavidcs * we loop. Explicitly null pointers after invalidation 1748284741Sdavidcs * to clarify operation. 1749284741Sdavidcs */ 1750284741Sdavidcs vput(ndp->ni_vp); 1751284741Sdavidcs ndp->ni_vp = NULL; 1752284741Sdavidcs 1753284741Sdavidcs if (cnp->cn_pnbuf[0] == '/') { 1754284741Sdavidcs vrele(ndp->ni_dvp); 1755284741Sdavidcs ndp->ni_dvp = ndp->ni_rootdir; 1756284741Sdavidcs VREF(ndp->ni_dvp); 1757284741Sdavidcs } 1758284741Sdavidcs ndp->ni_startdir = ndp->ni_dvp; 1759284741Sdavidcs ndp->ni_dvp = NULL; 1760284741Sdavidcs } 1761284741Sdavidcs 1762284741Sdavidcs /* 1763284741Sdavidcs * nfs_namei() guarentees that fields will not contain garbage 1764284741Sdavidcs * whether an error occurs or not. This allows the caller to track 1765284741Sdavidcs * cleanup state trivially. 1766284741Sdavidcs */ 1767284741Sdavidcsout: 1768284741Sdavidcs if (error) { 1769284741Sdavidcs zfree(namei_zone, cnp->cn_pnbuf); 1770284741Sdavidcs ndp->ni_vp = NULL; 1771284741Sdavidcs ndp->ni_dvp = NULL; 1772284741Sdavidcs ndp->ni_startdir = NULL; 1773284741Sdavidcs cnp->cn_flags &= ~HASBUF; 1774284741Sdavidcs } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 1775284741Sdavidcs ndp->ni_dvp = NULL; 1776284741Sdavidcs } 1777284741Sdavidcs return (error); 1778284741Sdavidcs} 1779284741Sdavidcs 1780284741Sdavidcs/* 1781284741Sdavidcs * A fiddled version of m_adj() that ensures null fill to a long 1782284741Sdavidcs * boundary and only trims off the back end 1783284741Sdavidcs */ 1784284741Sdavidcsvoid 1785284741Sdavidcsnfsm_adj(mp, len, nul) 1786284741Sdavidcs struct mbuf *mp; 1787284741Sdavidcs register int len; 1788284741Sdavidcs int nul; 1789284741Sdavidcs{ 1790284741Sdavidcs register struct mbuf *m; 1791284741Sdavidcs register int count, i; 1792284741Sdavidcs register char *cp; 1793284741Sdavidcs 1794284741Sdavidcs /* 1795284741Sdavidcs * Trim from tail. Scan the mbuf chain, 1796284741Sdavidcs * calculating its length and finding the last mbuf. 1797284741Sdavidcs * If the adjustment only affects this mbuf, then just 1798284741Sdavidcs * adjust and return. Otherwise, rescan and truncate 1799284741Sdavidcs * after the remaining size. 1800284741Sdavidcs */ 1801284741Sdavidcs count = 0; 1802284741Sdavidcs m = mp; 1803284741Sdavidcs for (;;) { 1804284741Sdavidcs count += m->m_len; 1805284741Sdavidcs if (m->m_next == (struct mbuf *)0) 1806284741Sdavidcs break; 1807284741Sdavidcs m = m->m_next; 1808284741Sdavidcs } 1809284741Sdavidcs if (m->m_len > len) { 1810284741Sdavidcs m->m_len -= len; 1811284741Sdavidcs if (nul > 0) { 1812284741Sdavidcs cp = mtod(m, caddr_t)+m->m_len-nul; 1813284741Sdavidcs for (i = 0; i < nul; i++) 1814284741Sdavidcs *cp++ = '\0'; 1815284741Sdavidcs } 1816284741Sdavidcs return; 1817284741Sdavidcs } 1818284741Sdavidcs count -= len; 1819284741Sdavidcs if (count < 0) 1820284741Sdavidcs count = 0; 1821284741Sdavidcs /* 1822284741Sdavidcs * Correct length for chain is "count". 1823284741Sdavidcs * Find the mbuf with last data, adjust its length, 1824284741Sdavidcs * and toss data from remaining mbufs on chain. 1825284741Sdavidcs */ 1826284741Sdavidcs for (m = mp; m; m = m->m_next) { 1827284741Sdavidcs if (m->m_len >= count) { 1828284741Sdavidcs m->m_len = count; 1829284741Sdavidcs if (nul > 0) { 1830284741Sdavidcs cp = mtod(m, caddr_t)+m->m_len-nul; 1831284741Sdavidcs for (i = 0; i < nul; i++) 1832284741Sdavidcs *cp++ = '\0'; 1833284741Sdavidcs } 1834284741Sdavidcs break; 1835284741Sdavidcs } 1836284741Sdavidcs count -= m->m_len; 1837284741Sdavidcs } 1838284741Sdavidcs for (m = m->m_next;m;m = m->m_next) 1839284741Sdavidcs m->m_len = 0; 1840284741Sdavidcs} 1841284741Sdavidcs 1842284741Sdavidcs/* 1843284741Sdavidcs * Make these functions instead of macros, so that the kernel text size 1844284741Sdavidcs * doesn't get too big... 1845284741Sdavidcs */ 1846284741Sdavidcsvoid 1847284741Sdavidcsnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 1848284741Sdavidcs struct nfsrv_descript *nfsd; 1849284741Sdavidcs int before_ret; 1850284741Sdavidcs register struct vattr *before_vap; 1851284741Sdavidcs int after_ret; 1852284741Sdavidcs struct vattr *after_vap; 1853284741Sdavidcs struct mbuf **mbp; 1854284741Sdavidcs char **bposp; 1855284741Sdavidcs{ 1856284741Sdavidcs register struct mbuf *mb = *mbp, *mb2; 1857284741Sdavidcs register char *bpos = *bposp; 1858284741Sdavidcs register u_int32_t *tl; 1859284741Sdavidcs 1860284741Sdavidcs if (before_ret) { 1861284741Sdavidcs nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1862284741Sdavidcs *tl = nfs_false; 1863284741Sdavidcs } else { 1864284741Sdavidcs nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 1865284741Sdavidcs *tl++ = nfs_true; 1866284741Sdavidcs txdr_hyper(before_vap->va_size, tl); 1867284741Sdavidcs tl += 2; 1868284741Sdavidcs txdr_nfsv3time(&(before_vap->va_mtime), tl); 1869284741Sdavidcs tl += 2; 1870284741Sdavidcs txdr_nfsv3time(&(before_vap->va_ctime), tl); 1871284741Sdavidcs } 1872284741Sdavidcs *bposp = bpos; 1873284741Sdavidcs *mbp = mb; 1874284741Sdavidcs nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1875284741Sdavidcs} 1876284741Sdavidcs 1877284741Sdavidcsvoid 1878284741Sdavidcsnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 1879284741Sdavidcs struct nfsrv_descript *nfsd; 1880284741Sdavidcs int after_ret; 1881284741Sdavidcs struct vattr *after_vap; 1882284741Sdavidcs struct mbuf **mbp; 1883284741Sdavidcs char **bposp; 1884284741Sdavidcs{ 1885284741Sdavidcs register struct mbuf *mb = *mbp, *mb2; 1886284741Sdavidcs register char *bpos = *bposp; 1887284741Sdavidcs register u_int32_t *tl; 1888284741Sdavidcs register struct nfs_fattr *fp; 1889284741Sdavidcs 1890284741Sdavidcs if (after_ret) { 1891284741Sdavidcs nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1892284741Sdavidcs *tl = nfs_false; 1893284741Sdavidcs } else { 1894284741Sdavidcs nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1895284741Sdavidcs *tl++ = nfs_true; 1896284741Sdavidcs fp = (struct nfs_fattr *)tl; 1897284741Sdavidcs nfsm_srvfattr(nfsd, after_vap, fp); 1898284741Sdavidcs } 1899284741Sdavidcs *mbp = mb; 1900284741Sdavidcs *bposp = bpos; 1901284741Sdavidcs} 1902284741Sdavidcs 1903284741Sdavidcsvoid 1904284741Sdavidcsnfsm_srvfattr(nfsd, vap, fp) 1905284741Sdavidcs register struct nfsrv_descript *nfsd; 1906284741Sdavidcs register struct vattr *vap; 1907284741Sdavidcs register struct nfs_fattr *fp; 1908284741Sdavidcs{ 1909284741Sdavidcs 1910284741Sdavidcs fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1911284741Sdavidcs fp->fa_uid = txdr_unsigned(vap->va_uid); 1912284741Sdavidcs fp->fa_gid = txdr_unsigned(vap->va_gid); 1913284741Sdavidcs if (nfsd->nd_flag & ND_NFSV3) { 1914284741Sdavidcs fp->fa_type = vtonfsv3_type(vap->va_type); 1915284741Sdavidcs fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1916284741Sdavidcs txdr_hyper(vap->va_size, &fp->fa3_size); 1917284741Sdavidcs txdr_hyper(vap->va_bytes, &fp->fa3_used); 1918284741Sdavidcs fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 1919284741Sdavidcs fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 1920284741Sdavidcs fp->fa3_fsid.nfsuquad[0] = 0; 1921284741Sdavidcs fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1922284741Sdavidcs fp->fa3_fileid.nfsuquad[0] = 0; 1923284741Sdavidcs fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1924284741Sdavidcs txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1925284741Sdavidcs txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1926284741Sdavidcs txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1927284741Sdavidcs } else { 1928284741Sdavidcs fp->fa_type = vtonfsv2_type(vap->va_type); 1929284741Sdavidcs fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1930284741Sdavidcs fp->fa2_size = txdr_unsigned(vap->va_size); 1931284741Sdavidcs fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1932284741Sdavidcs if (vap->va_type == VFIFO) 1933284741Sdavidcs fp->fa2_rdev = 0xffffffff; 1934284741Sdavidcs else 1935284741Sdavidcs fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1936284741Sdavidcs fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1937284741Sdavidcs fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1938284741Sdavidcs fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1939284741Sdavidcs txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1940284741Sdavidcs txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1941284741Sdavidcs txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1942284741Sdavidcs } 1943284741Sdavidcs} 1944284741Sdavidcs 1945284741Sdavidcs/* 1946284741Sdavidcs * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1947284741Sdavidcs * - look up fsid in mount list (if not found ret error) 1948284741Sdavidcs * - get vp and export rights by calling VFS_FHTOVP() 1949284741Sdavidcs * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1950284741Sdavidcs * - if not lockflag unlock it with VOP_UNLOCK() 1951284741Sdavidcs */ 1952284741Sdavidcsint 1953284741Sdavidcsnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 1954284741Sdavidcs fhandle_t *fhp; 1955284741Sdavidcs int lockflag; 1956284741Sdavidcs struct vnode **vpp; 1957284741Sdavidcs struct ucred *cred; 1958284741Sdavidcs struct nfssvc_sock *slp; 1959284741Sdavidcs struct sockaddr *nam; 1960284741Sdavidcs int *rdonlyp; 1961284741Sdavidcs int kerbflag; 1962284741Sdavidcs int pubflag; 1963284741Sdavidcs{ 1964284741Sdavidcs struct proc *p = curproc; /* XXX */ 1965284741Sdavidcs register struct mount *mp; 1966284741Sdavidcs register int i; 1967284741Sdavidcs struct ucred *credanon; 1968284741Sdavidcs int error, exflags; 1969284741Sdavidcs#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1970284741Sdavidcs struct sockaddr_int *saddr; 1971284741Sdavidcs#endif 1972284741Sdavidcs 1973284741Sdavidcs *vpp = (struct vnode *)0; 1974284741Sdavidcs 1975284741Sdavidcs if (nfs_ispublicfh(fhp)) { 1976284741Sdavidcs if (!pubflag || !nfs_pub.np_valid) 1977284741Sdavidcs return (ESTALE); 1978284741Sdavidcs fhp = &nfs_pub.np_handle; 1979284741Sdavidcs } 1980284741Sdavidcs 1981284741Sdavidcs mp = vfs_getvfs(&fhp->fh_fsid); 1982284741Sdavidcs if (!mp) 1983284741Sdavidcs return (ESTALE); 1984284741Sdavidcs error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 1985284741Sdavidcs if (error) 1986284741Sdavidcs return (error); 1987284741Sdavidcs#ifdef MNT_EXNORESPORT 1988284741Sdavidcs if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1989284741Sdavidcs saddr = (struct sockaddr_in *)nam; 1990284741Sdavidcs if (saddr->sin_family == AF_INET && 1991284741Sdavidcs ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1992284741Sdavidcs vput(*vpp); 1993284741Sdavidcs return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1994284741Sdavidcs } 1995284741Sdavidcs } 1996284741Sdavidcs#endif 1997284741Sdavidcs /* 1998284741Sdavidcs * Check/setup credentials. 1999284741Sdavidcs */ 2000284741Sdavidcs if (exflags & MNT_EXKERB) { 2001284741Sdavidcs if (!kerbflag) { 2002284741Sdavidcs vput(*vpp); 2003284741Sdavidcs return (NFSERR_AUTHERR | AUTH_TOOWEAK); 2004284741Sdavidcs } 2005284741Sdavidcs } else if (kerbflag) { 2006284741Sdavidcs vput(*vpp); 2007284741Sdavidcs return (NFSERR_AUTHERR | AUTH_TOOWEAK); 2008284741Sdavidcs } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 2009284741Sdavidcs cred->cr_uid = credanon->cr_uid; 2010284741Sdavidcs for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 2011284741Sdavidcs cred->cr_groups[i] = credanon->cr_groups[i]; 2012284741Sdavidcs cred->cr_ngroups = i; 2013284741Sdavidcs } 2014284741Sdavidcs if (exflags & MNT_EXRDONLY) 2015284741Sdavidcs *rdonlyp = 1; 2016284741Sdavidcs else 2017284741Sdavidcs *rdonlyp = 0; 2018284741Sdavidcs 2019284741Sdavidcs nfsrv_object_create(*vpp); 2020284741Sdavidcs 2021284741Sdavidcs if (!lockflag) 2022284741Sdavidcs VOP_UNLOCK(*vpp, 0, p); 2023284741Sdavidcs return (0); 2024284741Sdavidcs} 2025284741Sdavidcs 2026284741Sdavidcs 2027284741Sdavidcs/* 2028284741Sdavidcs * WebNFS: check if a filehandle is a public filehandle. For v3, this 2029284741Sdavidcs * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 2030284741Sdavidcs * transformed this to all zeroes in both cases, so check for it. 2031284741Sdavidcs */ 2032284741Sdavidcsint 2033284741Sdavidcsnfs_ispublicfh(fhp) 2034284741Sdavidcs fhandle_t *fhp; 2035284741Sdavidcs{ 2036284741Sdavidcs char *cp = (char *)fhp; 2037284741Sdavidcs int i; 2038284741Sdavidcs 2039284741Sdavidcs for (i = 0; i < NFSX_V3FH; i++) 2040284741Sdavidcs if (*cp++ != 0) 2041284741Sdavidcs return (FALSE); 2042284741Sdavidcs return (TRUE); 2043284741Sdavidcs} 2044284741Sdavidcs 2045284741Sdavidcs#endif /* NFS_NOSERVER */ 2046284741Sdavidcs/* 2047284741Sdavidcs * This function compares two net addresses by family and returns TRUE 2048284741Sdavidcs * if they are the same host. 2049284741Sdavidcs * If there is any doubt, return FALSE. 2050284741Sdavidcs * The AF_INET family is handled as a special case so that address mbufs 2051284741Sdavidcs * don't need to be saved to store "struct in_addr", which is only 4 bytes. 2052284741Sdavidcs */ 2053284741Sdavidcsint 2054284741Sdavidcsnetaddr_match(family, haddr, nam) 2055284741Sdavidcs int family; 2056284741Sdavidcs union nethostaddr *haddr; 2057284741Sdavidcs struct sockaddr *nam; 2058284741Sdavidcs{ 2059284741Sdavidcs register struct sockaddr_in *inetaddr; 2060284741Sdavidcs 2061284741Sdavidcs switch (family) { 2062284741Sdavidcs case AF_INET: 2063284741Sdavidcs inetaddr = (struct sockaddr_in *)nam; 2064284741Sdavidcs if (inetaddr->sin_family == AF_INET && 2065284741Sdavidcs inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 2066284741Sdavidcs return (1); 2067284741Sdavidcs break; 2068284741Sdavidcs#ifdef ISO 2069284741Sdavidcs case AF_ISO: 2070284741Sdavidcs { 2071284741Sdavidcs register struct sockaddr_iso *isoaddr1, *isoaddr2; 2072284741Sdavidcs 2073284741Sdavidcs isoaddr1 = (struct sockaddr_iso *)nam; 2074284741Sdavidcs isoaddr2 = (struct sockaddr_iso *)haddr->had_nam; 2075284741Sdavidcs if (isoaddr1->siso_family == AF_ISO && 2076284741Sdavidcs isoaddr1->siso_nlen > 0 && 2077284741Sdavidcs isoaddr1->siso_nlen == isoaddr2->siso_nlen && 2078284741Sdavidcs SAME_ISOADDR(isoaddr1, isoaddr2)) 2079284741Sdavidcs return (1); 2080284741Sdavidcs break; 2081284741Sdavidcs } 2082284741Sdavidcs#endif /* ISO */ 2083284741Sdavidcs default: 2084284741Sdavidcs break; 2085284741Sdavidcs }; 2086284741Sdavidcs return (0); 2087284741Sdavidcs} 2088284741Sdavidcs 2089284741Sdavidcsstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 2090284741Sdavidcs/* 2091284741Sdavidcs * This function finds the directory cookie that corresponds to the 2092284741Sdavidcs * logical byte offset given. 2093284741Sdavidcs */ 2094284741Sdavidcsnfsuint64 * 2095284741Sdavidcsnfs_getcookie(np, off, add) 2096284741Sdavidcs register struct nfsnode *np; 2097284741Sdavidcs off_t off; 2098284741Sdavidcs int add; 2099284741Sdavidcs{ 2100284741Sdavidcs register struct nfsdmap *dp, *dp2; 2101284741Sdavidcs register int pos; 2102284741Sdavidcs 2103284741Sdavidcs pos = (uoff_t)off / NFS_DIRBLKSIZ; 2104284741Sdavidcs if (pos == 0 || off < 0) { 2105284741Sdavidcs#ifdef DIAGNOSTIC 2106284741Sdavidcs if (add) 2107284741Sdavidcs panic("nfs getcookie add at <= 0"); 2108284741Sdavidcs#endif 2109284741Sdavidcs return (&nfs_nullcookie); 2110284741Sdavidcs } 2111284741Sdavidcs pos--; 2112284741Sdavidcs dp = np->n_cookies.lh_first; 2113284741Sdavidcs if (!dp) { 2114284741Sdavidcs if (add) { 2115284741Sdavidcs MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 2116284741Sdavidcs M_NFSDIROFF, M_WAITOK); 2117284741Sdavidcs dp->ndm_eocookie = 0; 2118284741Sdavidcs LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 2119284741Sdavidcs } else 2120284741Sdavidcs return ((nfsuint64 *)0); 2121284741Sdavidcs } 2122284741Sdavidcs while (pos >= NFSNUMCOOKIES) { 2123284741Sdavidcs pos -= NFSNUMCOOKIES; 2124284741Sdavidcs if (dp->ndm_list.le_next) { 2125284741Sdavidcs if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 2126284741Sdavidcs pos >= dp->ndm_eocookie) 2127284741Sdavidcs return ((nfsuint64 *)0); 2128284741Sdavidcs dp = dp->ndm_list.le_next; 2129284741Sdavidcs } else if (add) { 2130284741Sdavidcs MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 2131284741Sdavidcs M_NFSDIROFF, M_WAITOK); 2132284741Sdavidcs dp2->ndm_eocookie = 0; 2133284741Sdavidcs LIST_INSERT_AFTER(dp, dp2, ndm_list); 2134284741Sdavidcs dp = dp2; 2135284741Sdavidcs } else 2136284741Sdavidcs return ((nfsuint64 *)0); 2137284741Sdavidcs } 2138284741Sdavidcs if (pos >= dp->ndm_eocookie) { 2139284741Sdavidcs if (add) 2140284741Sdavidcs dp->ndm_eocookie = pos + 1; 2141284741Sdavidcs else 2142284741Sdavidcs return ((nfsuint64 *)0); 2143284741Sdavidcs } 2144284741Sdavidcs return (&dp->ndm_cookies[pos]); 2145284741Sdavidcs} 2146284741Sdavidcs 2147284741Sdavidcs/* 2148284741Sdavidcs * Invalidate cached directory information, except for the actual directory 2149284741Sdavidcs * blocks (which are invalidated separately). 2150284741Sdavidcs * Done mainly to avoid the use of stale offset cookies. 2151284741Sdavidcs */ 2152284741Sdavidcsvoid 2153284741Sdavidcsnfs_invaldir(vp) 2154284741Sdavidcs register struct vnode *vp; 2155284741Sdavidcs{ 2156284741Sdavidcs register struct nfsnode *np = VTONFS(vp); 2157284741Sdavidcs 2158284741Sdavidcs#ifdef DIAGNOSTIC 2159284741Sdavidcs if (vp->v_type != VDIR) 2160284741Sdavidcs panic("nfs: invaldir not dir"); 2161284741Sdavidcs#endif 2162284741Sdavidcs np->n_direofoffset = 0; 2163284741Sdavidcs np->n_cookieverf.nfsuquad[0] = 0; 2164284741Sdavidcs np->n_cookieverf.nfsuquad[1] = 0; 2165284741Sdavidcs if (np->n_cookies.lh_first) 2166284741Sdavidcs np->n_cookies.lh_first->ndm_eocookie = 0; 2167284741Sdavidcs} 2168284741Sdavidcs 2169284741Sdavidcs/* 2170284741Sdavidcs * The write verifier has changed (probably due to a server reboot), so all 2171284741Sdavidcs * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 2172284741Sdavidcs * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 2173284741Sdavidcs * flag. Once done the new write verifier can be set for the mount point. 2174284741Sdavidcs */ 2175284741Sdavidcsvoid 2176284741Sdavidcsnfs_clearcommit(mp) 2177284741Sdavidcs struct mount *mp; 2178284741Sdavidcs{ 2179284741Sdavidcs register struct vnode *vp, *nvp; 2180284741Sdavidcs register struct buf *bp, *nbp; 2181284741Sdavidcs int s; 2182284741Sdavidcs 2183284741Sdavidcs s = splbio(); 2184284741Sdavidcsloop: 2185284741Sdavidcs for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 2186284741Sdavidcs if (vp->v_mount != mp) /* Paranoia */ 2187284741Sdavidcs goto loop; 2188284741Sdavidcs nvp = vp->v_mntvnodes.le_next; 2189284741Sdavidcs for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 2190284741Sdavidcs nbp = TAILQ_NEXT(bp, b_vnbufs); 2191284741Sdavidcs if (BUF_REFCNT(bp) == 0 && 2192284741Sdavidcs (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 2193284741Sdavidcs == (B_DELWRI | B_NEEDCOMMIT)) 2194284741Sdavidcs bp->b_flags &= ~B_NEEDCOMMIT; 2195284741Sdavidcs } 2196284741Sdavidcs } 2197284741Sdavidcs splx(s); 2198284741Sdavidcs} 2199284741Sdavidcs 2200284741Sdavidcs#ifndef NFS_NOSERVER 2201284741Sdavidcs/* 2202284741Sdavidcs * Map errnos to NFS error numbers. For Version 3 also filter out error 2203284741Sdavidcs * numbers not specified for the associated procedure. 2204284741Sdavidcs */ 2205284741Sdavidcsint 2206284741Sdavidcsnfsrv_errmap(nd, err) 2207284741Sdavidcs struct nfsrv_descript *nd; 2208284741Sdavidcs register int err; 2209284741Sdavidcs{ 2210284741Sdavidcs register short *defaulterrp, *errp; 2211284741Sdavidcs 2212284741Sdavidcs if (nd->nd_flag & ND_NFSV3) { 2213284741Sdavidcs if (nd->nd_procnum <= NFSPROC_COMMIT) { 2214284741Sdavidcs errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 2215284741Sdavidcs while (*++errp) { 2216284741Sdavidcs if (*errp == err) 2217284741Sdavidcs return (err); 2218284741Sdavidcs else if (*errp > err) 2219284741Sdavidcs break; 2220284741Sdavidcs } 2221284741Sdavidcs return ((int)*defaulterrp); 2222284741Sdavidcs } else 2223284741Sdavidcs return (err & 0xffff); 2224284741Sdavidcs } 2225284741Sdavidcs if (err <= ELAST) 2226284741Sdavidcs return ((int)nfsrv_v2errmap[err - 1]); 2227284741Sdavidcs return (NFSERR_IO); 2228284741Sdavidcs} 2229284741Sdavidcs 2230284741Sdavidcsint 2231284741Sdavidcsnfsrv_object_create(vp) 2232284741Sdavidcs struct vnode *vp; 2233284741Sdavidcs{ 2234284741Sdavidcs 2235284741Sdavidcs if (vp == NULL || vp->v_type != VREG) 2236284741Sdavidcs return (1); 2237284741Sdavidcs return (vfs_object_create(vp, curproc, 2238284741Sdavidcs curproc ? curproc->p_ucred : NULL)); 2239284741Sdavidcs} 2240284741Sdavidcs 2241284741Sdavidcs/* 2242284741Sdavidcs * Sort the group list in increasing numerical order. 2243284741Sdavidcs * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 2244284741Sdavidcs * that used to be here.) 2245284741Sdavidcs */ 2246284741Sdavidcsvoid 2247284741Sdavidcsnfsrvw_sort(list, num) 2248284741Sdavidcs register gid_t *list; 2249284741Sdavidcs register int num; 2250284741Sdavidcs{ 2251284741Sdavidcs register int i, j; 2252284741Sdavidcs gid_t v; 2253284741Sdavidcs 2254284741Sdavidcs /* Insertion sort. */ 2255284741Sdavidcs for (i = 1; i < num; i++) { 2256284741Sdavidcs v = list[i]; 2257284741Sdavidcs /* find correct slot for value v, moving others up */ 2258284741Sdavidcs for (j = i; --j >= 0 && v < list[j];) 2259284741Sdavidcs list[j + 1] = list[j]; 2260284741Sdavidcs list[j + 1] = v; 2261284741Sdavidcs } 2262284741Sdavidcs} 2263284741Sdavidcs 2264284741Sdavidcs/* 2265284741Sdavidcs * copy credentials making sure that the result can be compared with bcmp(). 2266284741Sdavidcs */ 2267284741Sdavidcsvoid 2268284741Sdavidcsnfsrv_setcred(incred, outcred) 2269284741Sdavidcs register struct ucred *incred, *outcred; 2270284741Sdavidcs{ 2271284741Sdavidcs register int i; 2272284741Sdavidcs 2273284741Sdavidcs bzero((caddr_t)outcred, sizeof (struct ucred)); 2274284741Sdavidcs outcred->cr_ref = 1; 2275284741Sdavidcs outcred->cr_uid = incred->cr_uid; 2276284741Sdavidcs outcred->cr_ngroups = incred->cr_ngroups; 2277284741Sdavidcs for (i = 0; i < incred->cr_ngroups; i++) 2278284741Sdavidcs outcred->cr_groups[i] = incred->cr_groups[i]; 2279284741Sdavidcs nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 2280284741Sdavidcs} 2281284741Sdavidcs#endif /* NFS_NOSERVER */ 2282284741Sdavidcs