nfs_subs.c revision 60938
167754Smsmith/* 267754Smsmith * Copyright (c) 1989, 1993 367754Smsmith * The Regents of the University of California. All rights reserved. 4117521Snjl * 567754Smsmith * This code is derived from software contributed to Berkeley by 667754Smsmith * Rick Macklem at The University of Guelph. 767754Smsmith * 867754Smsmith * Redistribution and use in source and binary forms, with or without 967754Smsmith * modification, are permitted provided that the following conditions 1067754Smsmith * are met: 1167754Smsmith * 1. Redistributions of source code must retain the above copyright 12114237Snjl * notice, this list of conditions and the following disclaimer. 1370243Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1467754Smsmith * notice, this list of conditions and the following disclaimer in the 1567754Smsmith * documentation and/or other materials provided with the distribution. 1667754Smsmith * 3. All advertising materials mentioning features or use of this software 1767754Smsmith * must display the following acknowledgement: 1867754Smsmith * This product includes software developed by the University of 1967754Smsmith * California, Berkeley and its contributors. 2067754Smsmith * 4. Neither the name of the University nor the names of its contributors 2167754Smsmith * may be used to endorse or promote products derived from this software 2267754Smsmith * without specific prior written permission. 2367754Smsmith * 2467754Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2567754Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2667754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2767754Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2867754Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2967754Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3067754Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3167754Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3267754Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3367754Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3467754Smsmith * SUCH DAMAGE. 3567754Smsmith * 3667754Smsmith * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 3767754Smsmith * $FreeBSD: head/sys/nfsclient/nfs_subs.c 60938 2000-05-26 02:09:24Z jake $ 3867754Smsmith */ 3967754Smsmith 4067754Smsmith/* 4167754Smsmith * These functions support the macros and help fiddle mbuf chains for 4267754Smsmith * the nfs op functions. They do things like create the rpc header and 4367754Smsmith * copy data between mbuf chains and uio lists. 4467754Smsmith */ 4567754Smsmith#include <sys/param.h> 4667754Smsmith#include <sys/systm.h> 4767754Smsmith#include <sys/kernel.h> 4867754Smsmith#include <sys/bio.h> 4967754Smsmith#include <sys/buf.h> 5067754Smsmith#include <sys/proc.h> 5167754Smsmith#include <sys/mount.h> 5267754Smsmith#include <sys/vnode.h> 5367754Smsmith#include <sys/namei.h> 5467754Smsmith#include <sys/mbuf.h> 5567754Smsmith#include <sys/socket.h> 5667754Smsmith#include <sys/stat.h> 5767754Smsmith#include <sys/malloc.h> 5867754Smsmith#include <sys/sysent.h> 5967754Smsmith#include <sys/syscall.h> 6067754Smsmith 6167754Smsmith#include <vm/vm.h> 6267754Smsmith#include <vm/vm_object.h> 6367754Smsmith#include <vm/vm_extern.h> 6467754Smsmith#include <vm/vm_zone.h> 6567754Smsmith 6667754Smsmith#include <nfs/rpcv2.h> 6767754Smsmith#include <nfs/nfsproto.h> 6867754Smsmith#include <nfs/nfs.h> 6967754Smsmith#include <nfs/nfsnode.h> 7067754Smsmith#include <nfs/xdr_subs.h> 7167754Smsmith#include <nfs/nfsm_subs.h> 7267754Smsmith#include <nfs/nfsmount.h> 7367754Smsmith#include <nfs/nqnfs.h> 7467754Smsmith#include <nfs/nfsrtt.h> 7567754Smsmith 7667754Smsmith#include <netinet/in.h> 7767754Smsmith 7867754Smsmith/* 7967754Smsmith * Data items converted to xdr at startup, since they are constant 8067754Smsmith * This is kinda hokey, but may save a little time doing byte swaps 8167754Smsmith */ 8267754Smsmithu_int32_t nfs_xdrneg1; 8367754Smsmithu_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 8467754Smsmith rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 8567754Smsmith rpc_auth_kerb; 8667754Smsmithu_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 8767754Smsmith 8867754Smsmith/* And other global data */ 8967754Smsmithstatic u_int32_t nfs_xid = 0; 9067754Smsmithstatic enum vtype nv2tov_type[8]= { 9167754Smsmith VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 9267754Smsmith}; 9367754Smsmithenum vtype nv3tov_type[8]= { 9467754Smsmith VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 9567754Smsmith}; 9667754Smsmith 9767754Smsmithint nfs_ticks; 9867754Smsmithint nfs_pbuf_freecnt = -1; /* start out unlimited */ 9967754Smsmith 10067754Smsmithstruct nfs_reqq nfs_reqq; 10167754Smsmithstruct nfssvc_sockhead nfssvc_sockhead; 10267754Smsmithint nfssvc_sockhead_flag; 10367754Smsmithstruct nfsd_head nfsd_head; 10467754Smsmithint nfsd_head_flag; 10567754Smsmithstruct nfs_bufq nfs_bufq; 10667754Smsmithstruct nqtimerhead nqtimerhead; 10767754Smsmithstruct nqfhhashhead *nqfhhashtbl; 10867754Smsmithu_long nqfhhash; 10967754Smsmith 11067754Smsmithstatic void (*nfs_prev_lease_updatetime) __P((int)); 11167754Smsmithstatic int nfs_prev_nfssvc_sy_narg; 11267754Smsmithstatic sy_call_t *nfs_prev_nfssvc_sy_call; 11367754Smsmith 11467754Smsmith#ifndef NFS_NOSERVER 11567754Smsmith 11667754Smsmithstatic vop_t *nfs_prev_vop_lease_check; 11767754Smsmith 11867754Smsmith/* 11967754Smsmith * Mapping of old NFS Version 2 RPC numbers to generic numbers. 12067754Smsmith */ 12167754Smsmithint nfsv3_procid[NFS_NPROCS] = { 12267754Smsmith NFSPROC_NULL, 12367754Smsmith NFSPROC_GETATTR, 12467754Smsmith NFSPROC_SETATTR, 12567754Smsmith NFSPROC_NOOP, 126102550Siwasaki NFSPROC_LOOKUP, 12767754Smsmith NFSPROC_READLINK, 128102550Siwasaki NFSPROC_READ, 12991116Smsmith NFSPROC_NOOP, 13067754Smsmith NFSPROC_WRITE, 13167754Smsmith NFSPROC_CREATE, 13267754Smsmith NFSPROC_REMOVE, 13367754Smsmith NFSPROC_RENAME, 134114237Snjl NFSPROC_LINK, 135114237Snjl NFSPROC_SYMLINK, 136114237Snjl NFSPROC_MKDIR, 137114237Snjl NFSPROC_RMDIR, 138114237Snjl NFSPROC_READDIR, 139114237Snjl NFSPROC_FSSTAT, 140114237Snjl NFSPROC_NOOP, 141114237Snjl NFSPROC_NOOP, 142114237Snjl NFSPROC_NOOP, 143114237Snjl NFSPROC_NOOP, 144114237Snjl NFSPROC_NOOP, 145114237Snjl NFSPROC_NOOP, 146114237Snjl NFSPROC_NOOP, 147114237Snjl NFSPROC_NOOP 148114237Snjl}; 149114237Snjl 150114237Snjl#endif /* NFS_NOSERVER */ 151114237Snjl/* 152114237Snjl * and the reverse mapping from generic to Version 2 procedure numbers 153114237Snjl */ 154114237Snjlint nfsv2_procid[NFS_NPROCS] = { 155114237Snjl NFSV2PROC_NULL, 156114237Snjl NFSV2PROC_GETATTR, 157114237Snjl NFSV2PROC_SETATTR, 158114237Snjl NFSV2PROC_LOOKUP, 159114237Snjl NFSV2PROC_NOOP, 160114237Snjl NFSV2PROC_READLINK, 161114237Snjl NFSV2PROC_READ, 162114237Snjl NFSV2PROC_WRITE, 163114237Snjl NFSV2PROC_CREATE, 164114237Snjl NFSV2PROC_MKDIR, 165114237Snjl NFSV2PROC_SYMLINK, 166114237Snjl NFSV2PROC_CREATE, 167114237Snjl NFSV2PROC_REMOVE, 168114237Snjl NFSV2PROC_RMDIR, 169114237Snjl NFSV2PROC_RENAME, 170114237Snjl NFSV2PROC_LINK, 171114237Snjl NFSV2PROC_READDIR, 172114237Snjl NFSV2PROC_NOOP, 173114237Snjl NFSV2PROC_STATFS, 17467754Smsmith NFSV2PROC_NOOP, 17567754Smsmith NFSV2PROC_NOOP, 17667754Smsmith NFSV2PROC_NOOP, 17767754Smsmith NFSV2PROC_NOOP, 17867754Smsmith NFSV2PROC_NOOP, 17967754Smsmith NFSV2PROC_NOOP, 18067754Smsmith NFSV2PROC_NOOP, 18167754Smsmith}; 18267754Smsmith 18367754Smsmith#ifndef NFS_NOSERVER 18467754Smsmith/* 18567754Smsmith * Maps errno values to nfs error numbers. 18667754Smsmith * Use NFSERR_IO as the catch all for ones not specifically defined in 18767754Smsmith * RFC 1094. 18867754Smsmith */ 18967754Smsmithstatic u_char nfsrv_v2errmap[ELAST] = { 19067754Smsmith NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 19167754Smsmith NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 19291116Smsmith NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 19367754Smsmith NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 19491116Smsmith NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 19567754Smsmith NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 19667754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 19767754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 19867754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 19967754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20067754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20167754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20267754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 20367754Smsmith NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 20467754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20567754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20667754Smsmith NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 20767754Smsmith NFSERR_IO /* << Last is 86 */ 20867754Smsmith}; 20967754Smsmith 21067754Smsmith/* 21167754Smsmith * Maps errno values to nfs error numbers. 21267754Smsmith * Although it is not obvious whether or not NFS clients really care if 21367754Smsmith * a returned error value is in the specified list for the procedure, the 21467754Smsmith * safest thing to do is filter them appropriately. For Version 2, the 21567754Smsmith * X/Open XNFS document is the only specification that defines error values 21667754Smsmith * for each RPC (The RFC simply lists all possible error values for all RPCs), 21767754Smsmith * so I have decided to not do this for Version 2. 21867754Smsmith * The first entry is the default error return and the rest are the valid 21967754Smsmith * errors for that RPC in increasing numeric order. 22069746Smsmith */ 22167754Smsmithstatic short nfsv3err_null[] = { 22282367Smsmith 0, 223117521Snjl 0, 224117521Snjl}; 22567754Smsmith 22667754Smsmithstatic short nfsv3err_getattr[] = { 22767754Smsmith NFSERR_IO, 22867754Smsmith NFSERR_IO, 22967754Smsmith NFSERR_STALE, 23067754Smsmith NFSERR_BADHANDLE, 23167754Smsmith NFSERR_SERVERFAULT, 23267754Smsmith 0, 23367754Smsmith}; 23467754Smsmith 23567754Smsmithstatic short nfsv3err_setattr[] = { 23667754Smsmith NFSERR_IO, 23767754Smsmith NFSERR_PERM, 23867754Smsmith NFSERR_IO, 23967754Smsmith NFSERR_ACCES, 24067754Smsmith NFSERR_INVAL, 24167754Smsmith NFSERR_NOSPC, 24267754Smsmith NFSERR_ROFS, 24367754Smsmith NFSERR_DQUOT, 24467754Smsmith NFSERR_STALE, 24567754Smsmith NFSERR_BADHANDLE, 24667754Smsmith NFSERR_NOT_SYNC, 24767754Smsmith NFSERR_SERVERFAULT, 24867754Smsmith 0, 24967754Smsmith}; 25067754Smsmith 25167754Smsmithstatic short nfsv3err_lookup[] = { 25267754Smsmith NFSERR_IO, 25367754Smsmith NFSERR_NOENT, 25467754Smsmith NFSERR_IO, 25567754Smsmith NFSERR_ACCES, 25667754Smsmith NFSERR_NOTDIR, 25767754Smsmith NFSERR_NAMETOL, 25867754Smsmith NFSERR_STALE, 25967754Smsmith NFSERR_BADHANDLE, 26067754Smsmith NFSERR_SERVERFAULT, 26167754Smsmith 0, 26267754Smsmith}; 26367754Smsmith 26482367Smsmithstatic short nfsv3err_access[] = { 26567754Smsmith NFSERR_IO, 26667754Smsmith NFSERR_IO, 26767754Smsmith NFSERR_STALE, 26871867Smsmith NFSERR_BADHANDLE, 26982367Smsmith NFSERR_SERVERFAULT, 27091116Smsmith 0, 27191116Smsmith}; 27291116Smsmith 27367754Smsmithstatic short nfsv3err_readlink[] = { 27467754Smsmith NFSERR_IO, 27567754Smsmith NFSERR_IO, 27667754Smsmith NFSERR_ACCES, 27767754Smsmith NFSERR_INVAL, 27867754Smsmith NFSERR_STALE, 27967754Smsmith NFSERR_BADHANDLE, 28067754Smsmith NFSERR_NOTSUPP, 28167754Smsmith NFSERR_SERVERFAULT, 28267754Smsmith 0, 28367754Smsmith}; 28467754Smsmith 28567754Smsmithstatic short nfsv3err_read[] = { 28667754Smsmith NFSERR_IO, 28767754Smsmith NFSERR_IO, 28867754Smsmith NFSERR_NXIO, 28999146Siwasaki NFSERR_ACCES, 290114237Snjl NFSERR_INVAL, 291114237Snjl NFSERR_STALE, 292117521Snjl NFSERR_BADHANDLE, 293117521Snjl NFSERR_SERVERFAULT, 294114237Snjl 0, 295114237Snjl}; 296114237Snjl 297114237Snjlstatic short nfsv3err_write[] = { 298114237Snjl NFSERR_IO, 29967754Smsmith NFSERR_IO, 30067754Smsmith NFSERR_ACCES, 30167754Smsmith NFSERR_INVAL, 30267754Smsmith NFSERR_FBIG, 30367754Smsmith NFSERR_NOSPC, 304117521Snjl NFSERR_ROFS, 305117521Snjl NFSERR_DQUOT, 30667754Smsmith NFSERR_STALE, 30767754Smsmith NFSERR_BADHANDLE, 30867754Smsmith NFSERR_SERVERFAULT, 30967754Smsmith 0, 31067754Smsmith}; 31167754Smsmith 31267754Smsmithstatic short nfsv3err_create[] = { 31367754Smsmith NFSERR_IO, 314107325Siwasaki NFSERR_IO, 31582367Smsmith NFSERR_ACCES, 31682367Smsmith NFSERR_EXIST, 31767754Smsmith NFSERR_NOTDIR, 31867754Smsmith NFSERR_NOSPC, 31982367Smsmith NFSERR_ROFS, 32067754Smsmith NFSERR_NAMETOL, 32182367Smsmith NFSERR_DQUOT, 32267754Smsmith NFSERR_STALE, 32367754Smsmith NFSERR_BADHANDLE, 32467754Smsmith NFSERR_NOTSUPP, 32582367Smsmith NFSERR_SERVERFAULT, 32667754Smsmith 0, 32782367Smsmith}; 32867754Smsmith 32967754Smsmithstatic short nfsv3err_mkdir[] = { 33067754Smsmith NFSERR_IO, 33182367Smsmith NFSERR_IO, 33267754Smsmith NFSERR_ACCES, 33367754Smsmith NFSERR_EXIST, 33469746Smsmith NFSERR_NOTDIR, 33567754Smsmith NFSERR_NOSPC, 33667754Smsmith NFSERR_ROFS, 33767754Smsmith NFSERR_NAMETOL, 33867754Smsmith NFSERR_DQUOT, 33967754Smsmith NFSERR_STALE, 34067754Smsmith NFSERR_BADHANDLE, 34167754Smsmith NFSERR_NOTSUPP, 34267754Smsmith NFSERR_SERVERFAULT, 34367754Smsmith 0, 34467754Smsmith}; 34567754Smsmith 34667754Smsmithstatic short nfsv3err_symlink[] = { 34767754Smsmith NFSERR_IO, 34867754Smsmith NFSERR_IO, 34967754Smsmith NFSERR_ACCES, 35067754Smsmith NFSERR_EXIST, 35167754Smsmith NFSERR_NOTDIR, 35267754Smsmith NFSERR_NOSPC, 35367754Smsmith NFSERR_ROFS, 354114237Snjl NFSERR_NAMETOL, 35567754Smsmith NFSERR_DQUOT, 35667754Smsmith NFSERR_STALE, 35767754Smsmith NFSERR_BADHANDLE, 35867754Smsmith NFSERR_NOTSUPP, 35967754Smsmith NFSERR_SERVERFAULT, 36067754Smsmith 0, 36167754Smsmith}; 36267754Smsmith 36391116Smsmithstatic short nfsv3err_mknod[] = { 36467754Smsmith NFSERR_IO, 36567754Smsmith NFSERR_IO, 36667754Smsmith NFSERR_ACCES, 36767754Smsmith NFSERR_EXIST, 36867754Smsmith NFSERR_NOTDIR, 36967754Smsmith NFSERR_NOSPC, 37067754Smsmith NFSERR_ROFS, 37167754Smsmith NFSERR_NAMETOL, 37267754Smsmith NFSERR_DQUOT, 37367754Smsmith NFSERR_STALE, 37467754Smsmith NFSERR_BADHANDLE, 37567754Smsmith NFSERR_NOTSUPP, 37667754Smsmith NFSERR_SERVERFAULT, 37767754Smsmith NFSERR_BADTYPE, 37867754Smsmith 0, 37967754Smsmith}; 38067754Smsmith 38167754Smsmithstatic short nfsv3err_remove[] = { 38267754Smsmith NFSERR_IO, 38367754Smsmith NFSERR_NOENT, 38467754Smsmith NFSERR_IO, 38567754Smsmith NFSERR_ACCES, 38667754Smsmith NFSERR_NOTDIR, 38767754Smsmith NFSERR_ROFS, 38867754Smsmith NFSERR_NAMETOL, 38967754Smsmith NFSERR_STALE, 39067754Smsmith NFSERR_BADHANDLE, 39167754Smsmith NFSERR_SERVERFAULT, 39267754Smsmith 0, 39367754Smsmith}; 39467754Smsmith 39567754Smsmithstatic short nfsv3err_rmdir[] = { 39667754Smsmith NFSERR_IO, 39767754Smsmith NFSERR_NOENT, 39867754Smsmith NFSERR_IO, 39967754Smsmith NFSERR_ACCES, 40067754Smsmith NFSERR_EXIST, 40167754Smsmith NFSERR_NOTDIR, 40267754Smsmith NFSERR_INVAL, 40367754Smsmith NFSERR_ROFS, 40467754Smsmith NFSERR_NAMETOL, 40567754Smsmith NFSERR_NOTEMPTY, 40667754Smsmith NFSERR_STALE, 40767754Smsmith NFSERR_BADHANDLE, 40867754Smsmith NFSERR_NOTSUPP, 40967754Smsmith NFSERR_SERVERFAULT, 41067754Smsmith 0, 41167754Smsmith}; 41299679Siwasaki 41367754Smsmithstatic short nfsv3err_rename[] = { 41467754Smsmith NFSERR_IO, 41567754Smsmith NFSERR_NOENT, 41667754Smsmith NFSERR_IO, 41784491Smsmith NFSERR_ACCES, 41867754Smsmith NFSERR_EXIST, 41967754Smsmith NFSERR_XDEV, 42091116Smsmith NFSERR_NOTDIR, 42184491Smsmith NFSERR_ISDIR, 42284491Smsmith NFSERR_INVAL, 42367754Smsmith NFSERR_NOSPC, 42467754Smsmith NFSERR_ROFS, 42567754Smsmith NFSERR_MLINK, 42667754Smsmith NFSERR_NAMETOL, 42799679Siwasaki NFSERR_NOTEMPTY, 42867754Smsmith NFSERR_DQUOT, 42999679Siwasaki NFSERR_STALE, 43067754Smsmith NFSERR_BADHANDLE, 43199679Siwasaki NFSERR_NOTSUPP, 43299679Siwasaki NFSERR_SERVERFAULT, 433117521Snjl 0, 43484491Smsmith}; 43584491Smsmith 43684491Smsmithstatic short nfsv3err_link[] = { 43784491Smsmith NFSERR_IO, 43867754Smsmith NFSERR_IO, 43999679Siwasaki NFSERR_ACCES, 44084491Smsmith NFSERR_EXIST, 44184491Smsmith NFSERR_XDEV, 44299679Siwasaki NFSERR_NOTDIR, 44384491Smsmith NFSERR_INVAL, 44499679Siwasaki NFSERR_NOSPC, 44584491Smsmith NFSERR_ROFS, 44684491Smsmith NFSERR_MLINK, 44784491Smsmith NFSERR_NAMETOL, 44884491Smsmith NFSERR_DQUOT, 44984491Smsmith NFSERR_STALE, 45099679Siwasaki NFSERR_BADHANDLE, 45184491Smsmith NFSERR_NOTSUPP, 45284491Smsmith NFSERR_SERVERFAULT, 45384491Smsmith 0, 45499679Siwasaki}; 45599679Siwasaki 45667754Smsmithstatic short nfsv3err_readdir[] = { 45767754Smsmith NFSERR_IO, 45867754Smsmith NFSERR_IO, 45967754Smsmith NFSERR_ACCES, 46099679Siwasaki NFSERR_NOTDIR, 46167754Smsmith NFSERR_STALE, 46267754Smsmith NFSERR_BADHANDLE, 46367754Smsmith NFSERR_BAD_COOKIE, 46467754Smsmith NFSERR_TOOSMALL, 46599679Siwasaki NFSERR_SERVERFAULT, 46667754Smsmith 0, 46767754Smsmith}; 46867754Smsmith 46967754Smsmithstatic short nfsv3err_readdirplus[] = { 47067754Smsmith NFSERR_IO, 47167754Smsmith NFSERR_IO, 47267754Smsmith NFSERR_ACCES, 47367754Smsmith NFSERR_NOTDIR, 47467754Smsmith NFSERR_STALE, 47567754Smsmith NFSERR_BADHANDLE, 47667754Smsmith NFSERR_BAD_COOKIE, 47784491Smsmith NFSERR_NOTSUPP, 47867754Smsmith NFSERR_TOOSMALL, 47967754Smsmith NFSERR_SERVERFAULT, 48067754Smsmith 0, 48167754Smsmith}; 48267754Smsmith 48367754Smsmithstatic short nfsv3err_fsstat[] = { 48467754Smsmith NFSERR_IO, 48567754Smsmith NFSERR_IO, 48667754Smsmith NFSERR_STALE, 48767754Smsmith NFSERR_BADHANDLE, 48867754Smsmith NFSERR_SERVERFAULT, 48967754Smsmith 0, 49067754Smsmith}; 49167754Smsmith 49267754Smsmithstatic short nfsv3err_fsinfo[] = { 49367754Smsmith NFSERR_STALE, 49467754Smsmith NFSERR_STALE, 49567754Smsmith NFSERR_BADHANDLE, 49667754Smsmith NFSERR_SERVERFAULT, 49791116Smsmith 0, 49891116Smsmith}; 49991116Smsmith 50067754Smsmithstatic short nfsv3err_pathconf[] = { 50167754Smsmith NFSERR_STALE, 50267754Smsmith NFSERR_STALE, 50367754Smsmith NFSERR_BADHANDLE, 504114237Snjl NFSERR_SERVERFAULT, 50567754Smsmith 0, 506114237Snjl}; 50767754Smsmith 50867754Smsmithstatic short nfsv3err_commit[] = { 50967754Smsmith NFSERR_IO, 51067754Smsmith NFSERR_IO, 51167754Smsmith NFSERR_STALE, 51267754Smsmith NFSERR_BADHANDLE, 51367754Smsmith NFSERR_SERVERFAULT, 51467754Smsmith 0, 51567754Smsmith}; 51667754Smsmith 51767754Smsmithstatic short *nfsrv_v3errmap[] = { 51867754Smsmith nfsv3err_null, 51967754Smsmith nfsv3err_getattr, 52067754Smsmith nfsv3err_setattr, 52167754Smsmith nfsv3err_lookup, 52291116Smsmith nfsv3err_access, 52391116Smsmith nfsv3err_readlink, 52491116Smsmith nfsv3err_read, 52591116Smsmith nfsv3err_write, 52691116Smsmith nfsv3err_create, 527117521Snjl nfsv3err_mkdir, 52867754Smsmith nfsv3err_symlink, 52967754Smsmith nfsv3err_mknod, 530117521Snjl nfsv3err_remove, 531117521Snjl nfsv3err_rmdir, 53267754Smsmith nfsv3err_rename, 53367754Smsmith nfsv3err_link, 53480062Smsmith nfsv3err_readdir, 53567754Smsmith nfsv3err_readdirplus, 53667754Smsmith nfsv3err_fsstat, 53767754Smsmith nfsv3err_fsinfo, 53867754Smsmith nfsv3err_pathconf, 539102550Siwasaki nfsv3err_commit, 54067754Smsmith}; 54167754Smsmith 542#endif /* NFS_NOSERVER */ 543 544extern struct nfsrtt nfsrtt; 545extern time_t nqnfsstarttime; 546extern int nqsrv_clockskew; 547extern int nqsrv_writeslack; 548extern int nqsrv_maxlease; 549extern struct nfsstats nfsstats; 550extern int nqnfs_piggy[NFS_NPROCS]; 551extern nfstype nfsv2_type[9]; 552extern nfstype nfsv3_type[9]; 553extern struct nfsnodehashhead *nfsnodehashtbl; 554extern u_long nfsnodehash; 555 556struct nfssvc_args; 557extern int nfssvc(struct proc *, struct nfssvc_args *, int *); 558 559LIST_HEAD(nfsnodehashhead, nfsnode); 560 561int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); 562 563u_quad_t 564nfs_curusec() 565{ 566 struct timeval tv; 567 568 getmicrotime(&tv); 569 return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec); 570} 571 572/* 573 * Create the header for an rpc request packet 574 * The hsiz is the size of the rest of the nfs request header. 575 * (just used to decide if a cluster is a good idea) 576 */ 577struct mbuf * 578nfsm_reqh(vp, procid, hsiz, bposp) 579 struct vnode *vp; 580 u_long procid; 581 int hsiz; 582 caddr_t *bposp; 583{ 584 register struct mbuf *mb; 585 register u_int32_t *tl; 586 register caddr_t bpos; 587 struct mbuf *mb2; 588 struct nfsmount *nmp; 589 int nqflag; 590 591 MGET(mb, M_WAIT, MT_DATA); 592 if (hsiz >= MINCLSIZE) 593 MCLGET(mb, M_WAIT); 594 mb->m_len = 0; 595 bpos = mtod(mb, caddr_t); 596 597 /* 598 * For NQNFS, add lease request. 599 */ 600 if (vp) { 601 nmp = VFSTONFS(vp->v_mount); 602 if (nmp->nm_flag & NFSMNT_NQNFS) { 603 nqflag = NQNFS_NEEDLEASE(vp, procid); 604 if (nqflag) { 605 nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 606 *tl++ = txdr_unsigned(nqflag); 607 *tl = txdr_unsigned(nmp->nm_leaseterm); 608 } else { 609 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 610 *tl = 0; 611 } 612 } 613 } 614 /* Finally, return values */ 615 *bposp = bpos; 616 return (mb); 617} 618 619/* 620 * Build the RPC header and fill in the authorization info. 621 * The authorization string argument is only used when the credentials 622 * come from outside of the kernel. 623 * Returns the head of the mbuf list. 624 */ 625struct mbuf * 626nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 627 verf_str, mrest, mrest_len, mbp, xidp) 628 register struct ucred *cr; 629 int nmflag; 630 int procid; 631 int auth_type; 632 int auth_len; 633 char *auth_str; 634 int verf_len; 635 char *verf_str; 636 struct mbuf *mrest; 637 int mrest_len; 638 struct mbuf **mbp; 639 u_int32_t *xidp; 640{ 641 register struct mbuf *mb; 642 register u_int32_t *tl; 643 register caddr_t bpos; 644 register int i; 645 struct mbuf *mreq, *mb2; 646 int siz, grpsiz, authsiz; 647 648 authsiz = nfsm_rndup(auth_len); 649 MGETHDR(mb, M_WAIT, MT_DATA); 650 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 651 MCLGET(mb, M_WAIT); 652 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 653 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 654 } else { 655 MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 656 } 657 mb->m_len = 0; 658 mreq = mb; 659 bpos = mtod(mb, caddr_t); 660 661 /* 662 * First the RPC header. 663 */ 664 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 665 666 /* Get a pretty random xid to start with */ 667 if (!nfs_xid) 668 nfs_xid = random(); 669 /* 670 * Skip zero xid if it should ever happen. 671 */ 672 if (++nfs_xid == 0) 673 nfs_xid++; 674 675 *tl++ = *xidp = txdr_unsigned(nfs_xid); 676 *tl++ = rpc_call; 677 *tl++ = rpc_vers; 678 if (nmflag & NFSMNT_NQNFS) { 679 *tl++ = txdr_unsigned(NQNFS_PROG); 680 *tl++ = txdr_unsigned(NQNFS_VER3); 681 } else { 682 *tl++ = txdr_unsigned(NFS_PROG); 683 if (nmflag & NFSMNT_NFSV3) 684 *tl++ = txdr_unsigned(NFS_VER3); 685 else 686 *tl++ = txdr_unsigned(NFS_VER2); 687 } 688 if (nmflag & NFSMNT_NFSV3) 689 *tl++ = txdr_unsigned(procid); 690 else 691 *tl++ = txdr_unsigned(nfsv2_procid[procid]); 692 693 /* 694 * And then the authorization cred. 695 */ 696 *tl++ = txdr_unsigned(auth_type); 697 *tl = txdr_unsigned(authsiz); 698 switch (auth_type) { 699 case RPCAUTH_UNIX: 700 nfsm_build(tl, u_int32_t *, auth_len); 701 *tl++ = 0; /* stamp ?? */ 702 *tl++ = 0; /* NULL hostname */ 703 *tl++ = txdr_unsigned(cr->cr_uid); 704 *tl++ = txdr_unsigned(cr->cr_groups[0]); 705 grpsiz = (auth_len >> 2) - 5; 706 *tl++ = txdr_unsigned(grpsiz); 707 for (i = 1; i <= grpsiz; i++) 708 *tl++ = txdr_unsigned(cr->cr_groups[i]); 709 break; 710 case RPCAUTH_KERB4: 711 siz = auth_len; 712 while (siz > 0) { 713 if (M_TRAILINGSPACE(mb) == 0) { 714 MGET(mb2, M_WAIT, MT_DATA); 715 if (siz >= MINCLSIZE) 716 MCLGET(mb2, M_WAIT); 717 mb->m_next = mb2; 718 mb = mb2; 719 mb->m_len = 0; 720 bpos = mtod(mb, caddr_t); 721 } 722 i = min(siz, M_TRAILINGSPACE(mb)); 723 bcopy(auth_str, bpos, i); 724 mb->m_len += i; 725 auth_str += i; 726 bpos += i; 727 siz -= i; 728 } 729 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 730 for (i = 0; i < siz; i++) 731 *bpos++ = '\0'; 732 mb->m_len += siz; 733 } 734 break; 735 }; 736 737 /* 738 * And the verifier... 739 */ 740 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 741 if (verf_str) { 742 *tl++ = txdr_unsigned(RPCAUTH_KERB4); 743 *tl = txdr_unsigned(verf_len); 744 siz = verf_len; 745 while (siz > 0) { 746 if (M_TRAILINGSPACE(mb) == 0) { 747 MGET(mb2, M_WAIT, MT_DATA); 748 if (siz >= MINCLSIZE) 749 MCLGET(mb2, M_WAIT); 750 mb->m_next = mb2; 751 mb = mb2; 752 mb->m_len = 0; 753 bpos = mtod(mb, caddr_t); 754 } 755 i = min(siz, M_TRAILINGSPACE(mb)); 756 bcopy(verf_str, bpos, i); 757 mb->m_len += i; 758 verf_str += i; 759 bpos += i; 760 siz -= i; 761 } 762 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 763 for (i = 0; i < siz; i++) 764 *bpos++ = '\0'; 765 mb->m_len += siz; 766 } 767 } else { 768 *tl++ = txdr_unsigned(RPCAUTH_NULL); 769 *tl = 0; 770 } 771 mb->m_next = mrest; 772 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 773 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 774 *mbp = mb; 775 return (mreq); 776} 777 778/* 779 * copies mbuf chain to the uio scatter/gather list 780 */ 781int 782nfsm_mbuftouio(mrep, uiop, siz, dpos) 783 struct mbuf **mrep; 784 register struct uio *uiop; 785 int siz; 786 caddr_t *dpos; 787{ 788 register char *mbufcp, *uiocp; 789 register int xfer, left, len; 790 register struct mbuf *mp; 791 long uiosiz, rem; 792 int error = 0; 793 794 mp = *mrep; 795 mbufcp = *dpos; 796 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 797 rem = nfsm_rndup(siz)-siz; 798 while (siz > 0) { 799 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 800 return (EFBIG); 801 left = uiop->uio_iov->iov_len; 802 uiocp = uiop->uio_iov->iov_base; 803 if (left > siz) 804 left = siz; 805 uiosiz = left; 806 while (left > 0) { 807 while (len == 0) { 808 mp = mp->m_next; 809 if (mp == NULL) 810 return (EBADRPC); 811 mbufcp = mtod(mp, caddr_t); 812 len = mp->m_len; 813 } 814 xfer = (left > len) ? len : left; 815#ifdef notdef 816 /* Not Yet.. */ 817 if (uiop->uio_iov->iov_op != NULL) 818 (*(uiop->uio_iov->iov_op)) 819 (mbufcp, uiocp, xfer); 820 else 821#endif 822 if (uiop->uio_segflg == UIO_SYSSPACE) 823 bcopy(mbufcp, uiocp, xfer); 824 else 825 copyout(mbufcp, uiocp, xfer); 826 left -= xfer; 827 len -= xfer; 828 mbufcp += xfer; 829 uiocp += xfer; 830 uiop->uio_offset += xfer; 831 uiop->uio_resid -= xfer; 832 } 833 if (uiop->uio_iov->iov_len <= siz) { 834 uiop->uio_iovcnt--; 835 uiop->uio_iov++; 836 } else { 837 uiop->uio_iov->iov_base += uiosiz; 838 uiop->uio_iov->iov_len -= uiosiz; 839 } 840 siz -= uiosiz; 841 } 842 *dpos = mbufcp; 843 *mrep = mp; 844 if (rem > 0) { 845 if (len < rem) 846 error = nfs_adv(mrep, dpos, rem, len); 847 else 848 *dpos += rem; 849 } 850 return (error); 851} 852 853/* 854 * copies a uio scatter/gather list to an mbuf chain. 855 * NOTE: can ony handle iovcnt == 1 856 */ 857int 858nfsm_uiotombuf(uiop, mq, siz, bpos) 859 register struct uio *uiop; 860 struct mbuf **mq; 861 int siz; 862 caddr_t *bpos; 863{ 864 register char *uiocp; 865 register struct mbuf *mp, *mp2; 866 register int xfer, left, mlen; 867 int uiosiz, clflg, rem; 868 char *cp; 869 870#ifdef DIAGNOSTIC 871 if (uiop->uio_iovcnt != 1) 872 panic("nfsm_uiotombuf: iovcnt != 1"); 873#endif 874 875 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 876 clflg = 1; 877 else 878 clflg = 0; 879 rem = nfsm_rndup(siz)-siz; 880 mp = mp2 = *mq; 881 while (siz > 0) { 882 left = uiop->uio_iov->iov_len; 883 uiocp = uiop->uio_iov->iov_base; 884 if (left > siz) 885 left = siz; 886 uiosiz = left; 887 while (left > 0) { 888 mlen = M_TRAILINGSPACE(mp); 889 if (mlen == 0) { 890 MGET(mp, M_WAIT, MT_DATA); 891 if (clflg) 892 MCLGET(mp, M_WAIT); 893 mp->m_len = 0; 894 mp2->m_next = mp; 895 mp2 = mp; 896 mlen = M_TRAILINGSPACE(mp); 897 } 898 xfer = (left > mlen) ? mlen : left; 899#ifdef notdef 900 /* Not Yet.. */ 901 if (uiop->uio_iov->iov_op != NULL) 902 (*(uiop->uio_iov->iov_op)) 903 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 904 else 905#endif 906 if (uiop->uio_segflg == UIO_SYSSPACE) 907 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 908 else 909 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 910 mp->m_len += xfer; 911 left -= xfer; 912 uiocp += xfer; 913 uiop->uio_offset += xfer; 914 uiop->uio_resid -= xfer; 915 } 916 uiop->uio_iov->iov_base += uiosiz; 917 uiop->uio_iov->iov_len -= uiosiz; 918 siz -= uiosiz; 919 } 920 if (rem > 0) { 921 if (rem > M_TRAILINGSPACE(mp)) { 922 MGET(mp, M_WAIT, MT_DATA); 923 mp->m_len = 0; 924 mp2->m_next = mp; 925 } 926 cp = mtod(mp, caddr_t)+mp->m_len; 927 for (left = 0; left < rem; left++) 928 *cp++ = '\0'; 929 mp->m_len += rem; 930 *bpos = cp; 931 } else 932 *bpos = mtod(mp, caddr_t)+mp->m_len; 933 *mq = mp; 934 return (0); 935} 936 937/* 938 * Help break down an mbuf chain by setting the first siz bytes contiguous 939 * pointed to by returned val. 940 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 941 * cases. (The macros use the vars. dpos and dpos2) 942 */ 943int 944nfsm_disct(mdp, dposp, siz, left, cp2) 945 struct mbuf **mdp; 946 caddr_t *dposp; 947 int siz; 948 int left; 949 caddr_t *cp2; 950{ 951 register struct mbuf *mp, *mp2; 952 register int siz2, xfer; 953 register caddr_t p; 954 955 mp = *mdp; 956 while (left == 0) { 957 *mdp = mp = mp->m_next; 958 if (mp == NULL) 959 return (EBADRPC); 960 left = mp->m_len; 961 *dposp = mtod(mp, caddr_t); 962 } 963 if (left >= siz) { 964 *cp2 = *dposp; 965 *dposp += siz; 966 } else if (mp->m_next == NULL) { 967 return (EBADRPC); 968 } else if (siz > MHLEN) { 969 panic("nfs S too big"); 970 } else { 971 MGET(mp2, M_WAIT, MT_DATA); 972 mp2->m_next = mp->m_next; 973 mp->m_next = mp2; 974 mp->m_len -= left; 975 mp = mp2; 976 *cp2 = p = mtod(mp, caddr_t); 977 bcopy(*dposp, p, left); /* Copy what was left */ 978 siz2 = siz-left; 979 p += left; 980 mp2 = mp->m_next; 981 /* Loop around copying up the siz2 bytes */ 982 while (siz2 > 0) { 983 if (mp2 == NULL) 984 return (EBADRPC); 985 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 986 if (xfer > 0) { 987 bcopy(mtod(mp2, caddr_t), p, xfer); 988 NFSMADV(mp2, xfer); 989 mp2->m_len -= xfer; 990 p += xfer; 991 siz2 -= xfer; 992 } 993 if (siz2 > 0) 994 mp2 = mp2->m_next; 995 } 996 mp->m_len = siz; 997 *mdp = mp2; 998 *dposp = mtod(mp2, caddr_t); 999 } 1000 return (0); 1001} 1002 1003/* 1004 * Advance the position in the mbuf chain. 1005 */ 1006int 1007nfs_adv(mdp, dposp, offs, left) 1008 struct mbuf **mdp; 1009 caddr_t *dposp; 1010 int offs; 1011 int left; 1012{ 1013 register struct mbuf *m; 1014 register int s; 1015 1016 m = *mdp; 1017 s = left; 1018 while (s < offs) { 1019 offs -= s; 1020 m = m->m_next; 1021 if (m == NULL) 1022 return (EBADRPC); 1023 s = m->m_len; 1024 } 1025 *mdp = m; 1026 *dposp = mtod(m, caddr_t)+offs; 1027 return (0); 1028} 1029 1030/* 1031 * Copy a string into mbufs for the hard cases... 1032 */ 1033int 1034nfsm_strtmbuf(mb, bpos, cp, siz) 1035 struct mbuf **mb; 1036 char **bpos; 1037 const char *cp; 1038 long siz; 1039{ 1040 register struct mbuf *m1 = NULL, *m2; 1041 long left, xfer, len, tlen; 1042 u_int32_t *tl; 1043 int putsize; 1044 1045 putsize = 1; 1046 m2 = *mb; 1047 left = M_TRAILINGSPACE(m2); 1048 if (left > 0) { 1049 tl = ((u_int32_t *)(*bpos)); 1050 *tl++ = txdr_unsigned(siz); 1051 putsize = 0; 1052 left -= NFSX_UNSIGNED; 1053 m2->m_len += NFSX_UNSIGNED; 1054 if (left > 0) { 1055 bcopy(cp, (caddr_t) tl, left); 1056 siz -= left; 1057 cp += left; 1058 m2->m_len += left; 1059 left = 0; 1060 } 1061 } 1062 /* Loop around adding mbufs */ 1063 while (siz > 0) { 1064 MGET(m1, M_WAIT, MT_DATA); 1065 if (siz > MLEN) 1066 MCLGET(m1, M_WAIT); 1067 m1->m_len = NFSMSIZ(m1); 1068 m2->m_next = m1; 1069 m2 = m1; 1070 tl = mtod(m1, u_int32_t *); 1071 tlen = 0; 1072 if (putsize) { 1073 *tl++ = txdr_unsigned(siz); 1074 m1->m_len -= NFSX_UNSIGNED; 1075 tlen = NFSX_UNSIGNED; 1076 putsize = 0; 1077 } 1078 if (siz < m1->m_len) { 1079 len = nfsm_rndup(siz); 1080 xfer = siz; 1081 if (xfer < len) 1082 *(tl+(xfer>>2)) = 0; 1083 } else { 1084 xfer = len = m1->m_len; 1085 } 1086 bcopy(cp, (caddr_t) tl, xfer); 1087 m1->m_len = len+tlen; 1088 siz -= xfer; 1089 cp += xfer; 1090 } 1091 *mb = m1; 1092 *bpos = mtod(m1, caddr_t)+m1->m_len; 1093 return (0); 1094} 1095 1096/* 1097 * Called once to initialize data structures... 1098 */ 1099int 1100nfs_init(vfsp) 1101 struct vfsconf *vfsp; 1102{ 1103 register int i; 1104 1105 nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 1106 1107 nfs_mount_type = vfsp->vfc_typenum; 1108 nfsrtt.pos = 0; 1109 rpc_vers = txdr_unsigned(RPC_VER2); 1110 rpc_call = txdr_unsigned(RPC_CALL); 1111 rpc_reply = txdr_unsigned(RPC_REPLY); 1112 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 1113 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 1114 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 1115 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 1116 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1117 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 1118 nfs_prog = txdr_unsigned(NFS_PROG); 1119 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 1120 nfs_true = txdr_unsigned(TRUE); 1121 nfs_false = txdr_unsigned(FALSE); 1122 nfs_xdrneg1 = txdr_unsigned(-1); 1123 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1124 if (nfs_ticks < 1) 1125 nfs_ticks = 1; 1126 /* Ensure async daemons disabled */ 1127 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 1128 nfs_iodwant[i] = (struct proc *)0; 1129 nfs_iodmount[i] = (struct nfsmount *)0; 1130 } 1131 nfs_nhinit(); /* Init the nfsnode table */ 1132#ifndef NFS_NOSERVER 1133 nfsrv_init(0); /* Init server data structures */ 1134 nfsrv_initcache(); /* Init the server request cache */ 1135#endif 1136 1137 /* 1138 * Initialize the nqnfs server stuff. 1139 */ 1140 if (nqnfsstarttime == 0) { 1141 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 1142 + nqsrv_clockskew + nqsrv_writeslack; 1143 NQLOADNOVRAM(nqnfsstarttime); 1144 CIRCLEQ_INIT(&nqtimerhead); 1145 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 1146 } 1147 1148 /* 1149 * Initialize reply list and start timer 1150 */ 1151 TAILQ_INIT(&nfs_reqq); 1152 1153 nfs_timer(0); 1154 1155 /* 1156 * Set up lease_check and lease_updatetime so that other parts 1157 * of the system can call us, if we are loadable. 1158 */ 1159#ifndef NFS_NOSERVER 1160 nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)]; 1161 default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; 1162#endif 1163 nfs_prev_lease_updatetime = lease_updatetime; 1164 lease_updatetime = nfs_lease_updatetime; 1165 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 1166 sysent[SYS_nfssvc].sy_narg = 2; 1167 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 1168 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 1169 1170 nfs_pbuf_freecnt = nswbuf / 2 + 1; 1171 1172 return (0); 1173} 1174 1175int 1176nfs_uninit(vfsp) 1177 struct vfsconf *vfsp; 1178{ 1179 1180 untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 1181 nfs_mount_type = -1; 1182#ifndef NFS_NOSERVER 1183 default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check; 1184#endif 1185 lease_updatetime = nfs_prev_lease_updatetime; 1186 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 1187 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 1188 return (0); 1189} 1190 1191/* 1192 * Attribute cache routines. 1193 * nfs_loadattrcache() - loads or updates the cache contents from attributes 1194 * that are on the mbuf list 1195 * nfs_getattrcache() - returns valid attributes if found in cache, returns 1196 * error otherwise 1197 */ 1198 1199/* 1200 * Load the attribute cache (that lives in the nfsnode entry) with 1201 * the values on the mbuf list and 1202 * Iff vap not NULL 1203 * copy the attributes to *vaper 1204 */ 1205int 1206nfs_loadattrcache(vpp, mdp, dposp, vaper) 1207 struct vnode **vpp; 1208 struct mbuf **mdp; 1209 caddr_t *dposp; 1210 struct vattr *vaper; 1211{ 1212 register struct vnode *vp = *vpp; 1213 register struct vattr *vap; 1214 register struct nfs_fattr *fp; 1215 register struct nfsnode *np; 1216 register int32_t t1; 1217 caddr_t cp2; 1218 int error = 0, rdev; 1219 struct mbuf *md; 1220 enum vtype vtyp; 1221 u_short vmode; 1222 struct timespec mtime; 1223 int v3 = NFS_ISV3(vp); 1224 1225 md = *mdp; 1226 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1227 if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0) 1228 return (error); 1229 fp = (struct nfs_fattr *)cp2; 1230 if (v3) { 1231 vtyp = nfsv3tov_type(fp->fa_type); 1232 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1233 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 1234 fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 1235 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1236 } else { 1237 vtyp = nfsv2tov_type(fp->fa_type); 1238 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1239 /* 1240 * XXX 1241 * 1242 * The duplicate information returned in fa_type and fa_mode 1243 * is an ambiguity in the NFS version 2 protocol. 1244 * 1245 * VREG should be taken literally as a regular file. If a 1246 * server intents to return some type information differently 1247 * in the upper bits of the mode field (e.g. for sockets, or 1248 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 1249 * leave the examination of the mode bits even in the VREG 1250 * case to avoid breakage for bogus servers, but we make sure 1251 * that there are actually type bits set in the upper part of 1252 * fa_mode (and failing that, trust the va_type field). 1253 * 1254 * NFSv3 cleared the issue, and requires fa_mode to not 1255 * contain any type information (while also introduing sockets 1256 * and FIFOs for fa_type). 1257 */ 1258 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 1259 vtyp = IFTOVT(vmode); 1260 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 1261 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1262 1263 /* 1264 * Really ugly NFSv2 kludge. 1265 */ 1266 if (vtyp == VCHR && rdev == 0xffffffff) 1267 vtyp = VFIFO; 1268 } 1269 1270 /* 1271 * If v_type == VNON it is a new node, so fill in the v_type, 1272 * n_mtime fields. Check to see if it represents a special 1273 * device, and if so, check for a possible alias. Once the 1274 * correct vnode has been obtained, fill in the rest of the 1275 * information. 1276 */ 1277 np = VTONFS(vp); 1278 if (vp->v_type != vtyp) { 1279 vp->v_type = vtyp; 1280 if (vp->v_type == VFIFO) { 1281 vp->v_op = fifo_nfsv2nodeop_p; 1282 } 1283 if (vp->v_type == VCHR || vp->v_type == VBLK) { 1284 vp->v_op = spec_nfsv2nodeop_p; 1285 addaliasu(vp, rdev); 1286 } 1287 np->n_mtime = mtime.tv_sec; 1288 } 1289 vap = &np->n_vattr; 1290 vap->va_type = vtyp; 1291 vap->va_mode = (vmode & 07777); 1292 vap->va_rdev = rdev; 1293 vap->va_mtime = mtime; 1294 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1295 if (v3) { 1296 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1297 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1298 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1299 vap->va_size = fxdr_hyper(&fp->fa3_size); 1300 vap->va_blocksize = NFS_FABLKSIZE; 1301 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 1302 vap->va_fileid = fxdr_unsigned(int32_t, 1303 fp->fa3_fileid.nfsuquad[1]); 1304 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1305 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1306 vap->va_flags = 0; 1307 vap->va_filerev = 0; 1308 } else { 1309 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1310 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1311 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1312 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1313 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 1314 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 1315 * NFS_FABLKSIZE; 1316 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1317 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1318 vap->va_flags = 0; 1319 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 1320 fp->fa2_ctime.nfsv2_sec); 1321 vap->va_ctime.tv_nsec = 0; 1322 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 1323 vap->va_filerev = 0; 1324 } 1325 if (vap->va_size != np->n_size) { 1326 if (vap->va_type == VREG) { 1327 if (np->n_flag & NMODIFIED) { 1328 if (vap->va_size < np->n_size) 1329 vap->va_size = np->n_size; 1330 else 1331 np->n_size = vap->va_size; 1332 } else { 1333 np->n_size = vap->va_size; 1334 } 1335 vnode_pager_setsize(vp, np->n_size); 1336 } else { 1337 np->n_size = vap->va_size; 1338 } 1339 } 1340 np->n_attrstamp = time_second; 1341 if (vaper != NULL) { 1342 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 1343 if (np->n_flag & NCHG) { 1344 if (np->n_flag & NACC) 1345 vaper->va_atime = np->n_atim; 1346 if (np->n_flag & NUPD) 1347 vaper->va_mtime = np->n_mtim; 1348 } 1349 } 1350 return (0); 1351} 1352 1353#ifdef NFS_ACDEBUG 1354#include <sys/sysctl.h> 1355SYSCTL_DECL(_vfs_nfs); 1356static int nfs_acdebug; 1357SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 1358#endif 1359 1360/* 1361 * Check the time stamp 1362 * If the cache is valid, copy contents to *vap and return 0 1363 * otherwise return an error 1364 */ 1365int 1366nfs_getattrcache(vp, vaper) 1367 register struct vnode *vp; 1368 struct vattr *vaper; 1369{ 1370 register struct nfsnode *np; 1371 register struct vattr *vap; 1372 struct nfsmount *nmp; 1373 int timeo; 1374 1375 np = VTONFS(vp); 1376 vap = &np->n_vattr; 1377 nmp = VFSTONFS(vp->v_mount); 1378 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 1379 timeo = (time_second - np->n_mtime) / 10; 1380 1381#ifdef NFS_ACDEBUG 1382 if (nfs_acdebug>1) 1383 printf("nfs_getattrcache: initial timeo = %d\n", timeo); 1384#endif 1385 1386 if (vap->va_type == VDIR) { 1387 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 1388 timeo = nmp->nm_acdirmin; 1389 else if (timeo > nmp->nm_acdirmax) 1390 timeo = nmp->nm_acdirmax; 1391 } else { 1392 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 1393 timeo = nmp->nm_acregmin; 1394 else if (timeo > nmp->nm_acregmax) 1395 timeo = nmp->nm_acregmax; 1396 } 1397 1398#ifdef NFS_ACDEBUG 1399 if (nfs_acdebug > 2) 1400 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 1401 nmp->nm_acregmin, nmp->nm_acregmax, 1402 nmp->nm_acdirmin, nmp->nm_acdirmax); 1403 1404 if (nfs_acdebug) 1405 printf("nfs_getattrcache: age = %d; final timeo = %d\n", 1406 (time_second - np->n_attrstamp), timeo); 1407#endif 1408 1409 if ((time_second - np->n_attrstamp) >= timeo) { 1410 nfsstats.attrcache_misses++; 1411 return (ENOENT); 1412 } 1413 nfsstats.attrcache_hits++; 1414 if (vap->va_size != np->n_size) { 1415 if (vap->va_type == VREG) { 1416 if (np->n_flag & NMODIFIED) { 1417 if (vap->va_size < np->n_size) 1418 vap->va_size = np->n_size; 1419 else 1420 np->n_size = vap->va_size; 1421 } else { 1422 np->n_size = vap->va_size; 1423 } 1424 vnode_pager_setsize(vp, np->n_size); 1425 } else { 1426 np->n_size = vap->va_size; 1427 } 1428 } 1429 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 1430 if (np->n_flag & NCHG) { 1431 if (np->n_flag & NACC) 1432 vaper->va_atime = np->n_atim; 1433 if (np->n_flag & NUPD) 1434 vaper->va_mtime = np->n_mtim; 1435 } 1436 return (0); 1437} 1438 1439#ifndef NFS_NOSERVER 1440/* 1441 * Set up nameidata for a lookup() call and do it. 1442 * 1443 * If pubflag is set, this call is done for a lookup operation on the 1444 * public filehandle. In that case we allow crossing mountpoints and 1445 * absolute pathnames. However, the caller is expected to check that 1446 * the lookup result is within the public fs, and deny access if 1447 * it is not. 1448 * 1449 * nfs_namei() clears out garbage fields that namei() might leave garbage. 1450 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 1451 * error occurs but the parent was not requested. 1452 * 1453 * dirp may be set whether an error is returned or not, and must be 1454 * released by the caller. 1455 */ 1456int 1457nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) 1458 register struct nameidata *ndp; 1459 fhandle_t *fhp; 1460 int len; 1461 struct nfssvc_sock *slp; 1462 struct sockaddr *nam; 1463 struct mbuf **mdp; 1464 caddr_t *dposp; 1465 struct vnode **retdirp; 1466 struct proc *p; 1467 int kerbflag, pubflag; 1468{ 1469 register int i, rem; 1470 register struct mbuf *md; 1471 register char *fromcp, *tocp, *cp; 1472 struct iovec aiov; 1473 struct uio auio; 1474 struct vnode *dp; 1475 int error, rdonly, linklen; 1476 struct componentname *cnp = &ndp->ni_cnd; 1477 1478 *retdirp = (struct vnode *)0; 1479 cnp->cn_pnbuf = zalloc(namei_zone); 1480 1481 /* 1482 * Copy the name from the mbuf list to ndp->ni_pnbuf 1483 * and set the various ndp fields appropriately. 1484 */ 1485 fromcp = *dposp; 1486 tocp = cnp->cn_pnbuf; 1487 md = *mdp; 1488 rem = mtod(md, caddr_t) + md->m_len - fromcp; 1489 for (i = 0; i < len; i++) { 1490 while (rem == 0) { 1491 md = md->m_next; 1492 if (md == NULL) { 1493 error = EBADRPC; 1494 goto out; 1495 } 1496 fromcp = mtod(md, caddr_t); 1497 rem = md->m_len; 1498 } 1499 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 1500 error = EACCES; 1501 goto out; 1502 } 1503 *tocp++ = *fromcp++; 1504 rem--; 1505 } 1506 *tocp = '\0'; 1507 *mdp = md; 1508 *dposp = fromcp; 1509 len = nfsm_rndup(len)-len; 1510 if (len > 0) { 1511 if (rem >= len) 1512 *dposp += len; 1513 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 1514 goto out; 1515 } 1516 1517 /* 1518 * Extract and set starting directory. 1519 */ 1520 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 1521 nam, &rdonly, kerbflag, pubflag); 1522 if (error) 1523 goto out; 1524 if (dp->v_type != VDIR) { 1525 vrele(dp); 1526 error = ENOTDIR; 1527 goto out; 1528 } 1529 1530 if (rdonly) 1531 cnp->cn_flags |= RDONLY; 1532 1533 /* 1534 * Set return directory. Reference to dp is implicitly transfered 1535 * to the returned pointer 1536 */ 1537 *retdirp = dp; 1538 1539 if (pubflag) { 1540 /* 1541 * Oh joy. For WebNFS, handle those pesky '%' escapes, 1542 * and the 'native path' indicator. 1543 */ 1544 cp = zalloc(namei_zone); 1545 fromcp = cnp->cn_pnbuf; 1546 tocp = cp; 1547 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 1548 switch ((unsigned char)*fromcp) { 1549 case WEBNFS_NATIVE_CHAR: 1550 /* 1551 * 'Native' path for us is the same 1552 * as a path according to the NFS spec, 1553 * just skip the escape char. 1554 */ 1555 fromcp++; 1556 break; 1557 /* 1558 * More may be added in the future, range 0x80-0xff 1559 */ 1560 default: 1561 error = EIO; 1562 zfree(namei_zone, cp); 1563 goto out; 1564 } 1565 } 1566 /* 1567 * Translate the '%' escapes, URL-style. 1568 */ 1569 while (*fromcp != '\0') { 1570 if (*fromcp == WEBNFS_ESC_CHAR) { 1571 if (fromcp[1] != '\0' && fromcp[2] != '\0') { 1572 fromcp++; 1573 *tocp++ = HEXSTRTOI(fromcp); 1574 fromcp += 2; 1575 continue; 1576 } else { 1577 error = ENOENT; 1578 zfree(namei_zone, cp); 1579 goto out; 1580 } 1581 } else 1582 *tocp++ = *fromcp++; 1583 } 1584 *tocp = '\0'; 1585 zfree(namei_zone, cnp->cn_pnbuf); 1586 cnp->cn_pnbuf = cp; 1587 } 1588 1589 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 1590 ndp->ni_segflg = UIO_SYSSPACE; 1591 1592 if (pubflag) { 1593 ndp->ni_rootdir = rootvnode; 1594 ndp->ni_loopcnt = 0; 1595 if (cnp->cn_pnbuf[0] == '/') 1596 dp = rootvnode; 1597 } else { 1598 cnp->cn_flags |= NOCROSSMOUNT; 1599 } 1600 1601 /* 1602 * Initialize for scan, set ni_startdir and bump ref on dp again 1603 * becuase lookup() will dereference ni_startdir. 1604 */ 1605 1606 cnp->cn_proc = p; 1607 VREF(dp); 1608 ndp->ni_startdir = dp; 1609 1610 for (;;) { 1611 cnp->cn_nameptr = cnp->cn_pnbuf; 1612 /* 1613 * Call lookup() to do the real work. If an error occurs, 1614 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 1615 * we do not have to dereference anything before returning. 1616 * In either case ni_startdir will be dereferenced and NULLed 1617 * out. 1618 */ 1619 error = lookup(ndp); 1620 if (error) 1621 break; 1622 1623 /* 1624 * Check for encountering a symbolic link. Trivial 1625 * termination occurs if no symlink encountered. 1626 * Note: zfree is safe because error is 0, so we will 1627 * not zfree it again when we break. 1628 */ 1629 if ((cnp->cn_flags & ISSYMLINK) == 0) { 1630 nfsrv_object_create(ndp->ni_vp); 1631 if (cnp->cn_flags & (SAVENAME | SAVESTART)) 1632 cnp->cn_flags |= HASBUF; 1633 else 1634 zfree(namei_zone, cnp->cn_pnbuf); 1635 break; 1636 } 1637 1638 /* 1639 * Validate symlink 1640 */ 1641 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1642 VOP_UNLOCK(ndp->ni_dvp, 0, p); 1643 if (!pubflag) { 1644 error = EINVAL; 1645 goto badlink2; 1646 } 1647 1648 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 1649 error = ELOOP; 1650 goto badlink2; 1651 } 1652 if (ndp->ni_pathlen > 1) 1653 cp = zalloc(namei_zone); 1654 else 1655 cp = cnp->cn_pnbuf; 1656 aiov.iov_base = cp; 1657 aiov.iov_len = MAXPATHLEN; 1658 auio.uio_iov = &aiov; 1659 auio.uio_iovcnt = 1; 1660 auio.uio_offset = 0; 1661 auio.uio_rw = UIO_READ; 1662 auio.uio_segflg = UIO_SYSSPACE; 1663 auio.uio_procp = (struct proc *)0; 1664 auio.uio_resid = MAXPATHLEN; 1665 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 1666 if (error) { 1667 badlink1: 1668 if (ndp->ni_pathlen > 1) 1669 zfree(namei_zone, cp); 1670 badlink2: 1671 vrele(ndp->ni_dvp); 1672 vput(ndp->ni_vp); 1673 break; 1674 } 1675 linklen = MAXPATHLEN - auio.uio_resid; 1676 if (linklen == 0) { 1677 error = ENOENT; 1678 goto badlink1; 1679 } 1680 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 1681 error = ENAMETOOLONG; 1682 goto badlink1; 1683 } 1684 1685 /* 1686 * Adjust or replace path 1687 */ 1688 if (ndp->ni_pathlen > 1) { 1689 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 1690 zfree(namei_zone, cnp->cn_pnbuf); 1691 cnp->cn_pnbuf = cp; 1692 } else 1693 cnp->cn_pnbuf[linklen] = '\0'; 1694 ndp->ni_pathlen += linklen; 1695 1696 /* 1697 * Cleanup refs for next loop and check if root directory 1698 * should replace current directory. Normally ni_dvp 1699 * becomes the new base directory and is cleaned up when 1700 * we loop. Explicitly null pointers after invalidation 1701 * to clarify operation. 1702 */ 1703 vput(ndp->ni_vp); 1704 ndp->ni_vp = NULL; 1705 1706 if (cnp->cn_pnbuf[0] == '/') { 1707 vrele(ndp->ni_dvp); 1708 ndp->ni_dvp = ndp->ni_rootdir; 1709 VREF(ndp->ni_dvp); 1710 } 1711 ndp->ni_startdir = ndp->ni_dvp; 1712 ndp->ni_dvp = NULL; 1713 } 1714 1715 /* 1716 * nfs_namei() guarentees that fields will not contain garbage 1717 * whether an error occurs or not. This allows the caller to track 1718 * cleanup state trivially. 1719 */ 1720out: 1721 if (error) { 1722 zfree(namei_zone, cnp->cn_pnbuf); 1723 ndp->ni_vp = NULL; 1724 ndp->ni_dvp = NULL; 1725 ndp->ni_startdir = NULL; 1726 cnp->cn_flags &= ~HASBUF; 1727 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 1728 ndp->ni_dvp = NULL; 1729 } 1730 return (error); 1731} 1732 1733/* 1734 * A fiddled version of m_adj() that ensures null fill to a long 1735 * boundary and only trims off the back end 1736 */ 1737void 1738nfsm_adj(mp, len, nul) 1739 struct mbuf *mp; 1740 register int len; 1741 int nul; 1742{ 1743 register struct mbuf *m; 1744 register int count, i; 1745 register char *cp; 1746 1747 /* 1748 * Trim from tail. Scan the mbuf chain, 1749 * calculating its length and finding the last mbuf. 1750 * If the adjustment only affects this mbuf, then just 1751 * adjust and return. Otherwise, rescan and truncate 1752 * after the remaining size. 1753 */ 1754 count = 0; 1755 m = mp; 1756 for (;;) { 1757 count += m->m_len; 1758 if (m->m_next == (struct mbuf *)0) 1759 break; 1760 m = m->m_next; 1761 } 1762 if (m->m_len > len) { 1763 m->m_len -= len; 1764 if (nul > 0) { 1765 cp = mtod(m, caddr_t)+m->m_len-nul; 1766 for (i = 0; i < nul; i++) 1767 *cp++ = '\0'; 1768 } 1769 return; 1770 } 1771 count -= len; 1772 if (count < 0) 1773 count = 0; 1774 /* 1775 * Correct length for chain is "count". 1776 * Find the mbuf with last data, adjust its length, 1777 * and toss data from remaining mbufs on chain. 1778 */ 1779 for (m = mp; m; m = m->m_next) { 1780 if (m->m_len >= count) { 1781 m->m_len = count; 1782 if (nul > 0) { 1783 cp = mtod(m, caddr_t)+m->m_len-nul; 1784 for (i = 0; i < nul; i++) 1785 *cp++ = '\0'; 1786 } 1787 break; 1788 } 1789 count -= m->m_len; 1790 } 1791 for (m = m->m_next;m;m = m->m_next) 1792 m->m_len = 0; 1793} 1794 1795/* 1796 * Make these functions instead of macros, so that the kernel text size 1797 * doesn't get too big... 1798 */ 1799void 1800nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 1801 struct nfsrv_descript *nfsd; 1802 int before_ret; 1803 register struct vattr *before_vap; 1804 int after_ret; 1805 struct vattr *after_vap; 1806 struct mbuf **mbp; 1807 char **bposp; 1808{ 1809 register struct mbuf *mb = *mbp, *mb2; 1810 register char *bpos = *bposp; 1811 register u_int32_t *tl; 1812 1813 if (before_ret) { 1814 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1815 *tl = nfs_false; 1816 } else { 1817 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 1818 *tl++ = nfs_true; 1819 txdr_hyper(before_vap->va_size, tl); 1820 tl += 2; 1821 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1822 tl += 2; 1823 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1824 } 1825 *bposp = bpos; 1826 *mbp = mb; 1827 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1828} 1829 1830void 1831nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 1832 struct nfsrv_descript *nfsd; 1833 int after_ret; 1834 struct vattr *after_vap; 1835 struct mbuf **mbp; 1836 char **bposp; 1837{ 1838 register struct mbuf *mb = *mbp, *mb2; 1839 register char *bpos = *bposp; 1840 register u_int32_t *tl; 1841 register struct nfs_fattr *fp; 1842 1843 if (after_ret) { 1844 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1845 *tl = nfs_false; 1846 } else { 1847 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1848 *tl++ = nfs_true; 1849 fp = (struct nfs_fattr *)tl; 1850 nfsm_srvfattr(nfsd, after_vap, fp); 1851 } 1852 *mbp = mb; 1853 *bposp = bpos; 1854} 1855 1856void 1857nfsm_srvfattr(nfsd, vap, fp) 1858 register struct nfsrv_descript *nfsd; 1859 register struct vattr *vap; 1860 register struct nfs_fattr *fp; 1861{ 1862 1863 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1864 fp->fa_uid = txdr_unsigned(vap->va_uid); 1865 fp->fa_gid = txdr_unsigned(vap->va_gid); 1866 if (nfsd->nd_flag & ND_NFSV3) { 1867 fp->fa_type = vtonfsv3_type(vap->va_type); 1868 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1869 txdr_hyper(vap->va_size, &fp->fa3_size); 1870 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1871 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 1872 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 1873 fp->fa3_fsid.nfsuquad[0] = 0; 1874 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1875 fp->fa3_fileid.nfsuquad[0] = 0; 1876 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1877 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1878 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1879 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1880 } else { 1881 fp->fa_type = vtonfsv2_type(vap->va_type); 1882 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1883 fp->fa2_size = txdr_unsigned(vap->va_size); 1884 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1885 if (vap->va_type == VFIFO) 1886 fp->fa2_rdev = 0xffffffff; 1887 else 1888 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1889 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1890 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1891 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1892 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1893 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1894 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1895 } 1896} 1897 1898/* 1899 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1900 * - look up fsid in mount list (if not found ret error) 1901 * - get vp and export rights by calling VFS_FHTOVP() 1902 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1903 * - if not lockflag unlock it with VOP_UNLOCK() 1904 */ 1905int 1906nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) 1907 fhandle_t *fhp; 1908 int lockflag; 1909 struct vnode **vpp; 1910 struct ucred *cred; 1911 struct nfssvc_sock *slp; 1912 struct sockaddr *nam; 1913 int *rdonlyp; 1914 int kerbflag; 1915 int pubflag; 1916{ 1917 struct proc *p = curproc; /* XXX */ 1918 register struct mount *mp; 1919 register int i; 1920 struct ucred *credanon; 1921 int error, exflags; 1922#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1923 struct sockaddr_int *saddr; 1924#endif 1925 1926 *vpp = (struct vnode *)0; 1927 1928 if (nfs_ispublicfh(fhp)) { 1929 if (!pubflag || !nfs_pub.np_valid) 1930 return (ESTALE); 1931 fhp = &nfs_pub.np_handle; 1932 } 1933 1934 mp = vfs_getvfs(&fhp->fh_fsid); 1935 if (!mp) 1936 return (ESTALE); 1937 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1938 if (error) 1939 return (error); 1940 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1941 if (error) 1942 return (error); 1943#ifdef MNT_EXNORESPORT 1944 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1945 saddr = (struct sockaddr_in *)nam; 1946 if (saddr->sin_family == AF_INET && 1947 ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1948 vput(*vpp); 1949 *vpp = NULL; 1950 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1951 } 1952 } 1953#endif 1954 /* 1955 * Check/setup credentials. 1956 */ 1957 if (exflags & MNT_EXKERB) { 1958 if (!kerbflag) { 1959 vput(*vpp); 1960 *vpp = NULL; 1961 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1962 } 1963 } else if (kerbflag) { 1964 vput(*vpp); 1965 *vpp = NULL; 1966 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1967 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1968 cred->cr_uid = credanon->cr_uid; 1969 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1970 cred->cr_groups[i] = credanon->cr_groups[i]; 1971 cred->cr_ngroups = i; 1972 } 1973 if (exflags & MNT_EXRDONLY) 1974 *rdonlyp = 1; 1975 else 1976 *rdonlyp = 0; 1977 1978 nfsrv_object_create(*vpp); 1979 1980 if (!lockflag) 1981 VOP_UNLOCK(*vpp, 0, p); 1982 return (0); 1983} 1984 1985 1986/* 1987 * WebNFS: check if a filehandle is a public filehandle. For v3, this 1988 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 1989 * transformed this to all zeroes in both cases, so check for it. 1990 */ 1991int 1992nfs_ispublicfh(fhp) 1993 fhandle_t *fhp; 1994{ 1995 char *cp = (char *)fhp; 1996 int i; 1997 1998 for (i = 0; i < NFSX_V3FH; i++) 1999 if (*cp++ != 0) 2000 return (FALSE); 2001 return (TRUE); 2002} 2003 2004#endif /* NFS_NOSERVER */ 2005/* 2006 * This function compares two net addresses by family and returns TRUE 2007 * if they are the same host. 2008 * If there is any doubt, return FALSE. 2009 * The AF_INET family is handled as a special case so that address mbufs 2010 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 2011 */ 2012int 2013netaddr_match(family, haddr, nam) 2014 int family; 2015 union nethostaddr *haddr; 2016 struct sockaddr *nam; 2017{ 2018 register struct sockaddr_in *inetaddr; 2019 2020 switch (family) { 2021 case AF_INET: 2022 inetaddr = (struct sockaddr_in *)nam; 2023 if (inetaddr->sin_family == AF_INET && 2024 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 2025 return (1); 2026 break; 2027 default: 2028 break; 2029 }; 2030 return (0); 2031} 2032 2033static nfsuint64 nfs_nullcookie = { { 0, 0 } }; 2034/* 2035 * This function finds the directory cookie that corresponds to the 2036 * logical byte offset given. 2037 */ 2038nfsuint64 * 2039nfs_getcookie(np, off, add) 2040 register struct nfsnode *np; 2041 off_t off; 2042 int add; 2043{ 2044 register struct nfsdmap *dp, *dp2; 2045 register int pos; 2046 2047 pos = (uoff_t)off / NFS_DIRBLKSIZ; 2048 if (pos == 0 || off < 0) { 2049#ifdef DIAGNOSTIC 2050 if (add) 2051 panic("nfs getcookie add at <= 0"); 2052#endif 2053 return (&nfs_nullcookie); 2054 } 2055 pos--; 2056 dp = np->n_cookies.lh_first; 2057 if (!dp) { 2058 if (add) { 2059 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 2060 M_NFSDIROFF, M_WAITOK); 2061 dp->ndm_eocookie = 0; 2062 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 2063 } else 2064 return ((nfsuint64 *)0); 2065 } 2066 while (pos >= NFSNUMCOOKIES) { 2067 pos -= NFSNUMCOOKIES; 2068 if (dp->ndm_list.le_next) { 2069 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 2070 pos >= dp->ndm_eocookie) 2071 return ((nfsuint64 *)0); 2072 dp = dp->ndm_list.le_next; 2073 } else if (add) { 2074 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 2075 M_NFSDIROFF, M_WAITOK); 2076 dp2->ndm_eocookie = 0; 2077 LIST_INSERT_AFTER(dp, dp2, ndm_list); 2078 dp = dp2; 2079 } else 2080 return ((nfsuint64 *)0); 2081 } 2082 if (pos >= dp->ndm_eocookie) { 2083 if (add) 2084 dp->ndm_eocookie = pos + 1; 2085 else 2086 return ((nfsuint64 *)0); 2087 } 2088 return (&dp->ndm_cookies[pos]); 2089} 2090 2091/* 2092 * Invalidate cached directory information, except for the actual directory 2093 * blocks (which are invalidated separately). 2094 * Done mainly to avoid the use of stale offset cookies. 2095 */ 2096void 2097nfs_invaldir(vp) 2098 register struct vnode *vp; 2099{ 2100 register struct nfsnode *np = VTONFS(vp); 2101 2102#ifdef DIAGNOSTIC 2103 if (vp->v_type != VDIR) 2104 panic("nfs: invaldir not dir"); 2105#endif 2106 np->n_direofoffset = 0; 2107 np->n_cookieverf.nfsuquad[0] = 0; 2108 np->n_cookieverf.nfsuquad[1] = 0; 2109 if (np->n_cookies.lh_first) 2110 np->n_cookies.lh_first->ndm_eocookie = 0; 2111} 2112 2113/* 2114 * The write verifier has changed (probably due to a server reboot), so all 2115 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 2116 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 2117 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 2118 * mount point. 2119 * 2120 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 2121 * writes are not clusterable. 2122 */ 2123void 2124nfs_clearcommit(mp) 2125 struct mount *mp; 2126{ 2127 register struct vnode *vp, *nvp; 2128 register struct buf *bp, *nbp; 2129 int s; 2130 2131 s = splbio(); 2132loop: 2133 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 2134 if (vp->v_mount != mp) /* Paranoia */ 2135 goto loop; 2136 nvp = vp->v_mntvnodes.le_next; 2137 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 2138 nbp = TAILQ_NEXT(bp, b_vnbufs); 2139 if (BUF_REFCNT(bp) == 0 && 2140 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 2141 == (B_DELWRI | B_NEEDCOMMIT)) 2142 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 2143 } 2144 } 2145 splx(s); 2146} 2147 2148#ifndef NFS_NOSERVER 2149/* 2150 * Map errnos to NFS error numbers. For Version 3 also filter out error 2151 * numbers not specified for the associated procedure. 2152 */ 2153int 2154nfsrv_errmap(nd, err) 2155 struct nfsrv_descript *nd; 2156 register int err; 2157{ 2158 register short *defaulterrp, *errp; 2159 2160 if (nd->nd_flag & ND_NFSV3) { 2161 if (nd->nd_procnum <= NFSPROC_COMMIT) { 2162 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 2163 while (*++errp) { 2164 if (*errp == err) 2165 return (err); 2166 else if (*errp > err) 2167 break; 2168 } 2169 return ((int)*defaulterrp); 2170 } else 2171 return (err & 0xffff); 2172 } 2173 if (err <= ELAST) 2174 return ((int)nfsrv_v2errmap[err - 1]); 2175 return (NFSERR_IO); 2176} 2177 2178int 2179nfsrv_object_create(vp) 2180 struct vnode *vp; 2181{ 2182 2183 if (vp == NULL || vp->v_type != VREG) 2184 return (1); 2185 return (vfs_object_create(vp, curproc, 2186 curproc ? curproc->p_ucred : NULL)); 2187} 2188 2189/* 2190 * Sort the group list in increasing numerical order. 2191 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 2192 * that used to be here.) 2193 */ 2194void 2195nfsrvw_sort(list, num) 2196 register gid_t *list; 2197 register int num; 2198{ 2199 register int i, j; 2200 gid_t v; 2201 2202 /* Insertion sort. */ 2203 for (i = 1; i < num; i++) { 2204 v = list[i]; 2205 /* find correct slot for value v, moving others up */ 2206 for (j = i; --j >= 0 && v < list[j];) 2207 list[j + 1] = list[j]; 2208 list[j + 1] = v; 2209 } 2210} 2211 2212/* 2213 * copy credentials making sure that the result can be compared with bcmp(). 2214 */ 2215void 2216nfsrv_setcred(incred, outcred) 2217 register struct ucred *incred, *outcred; 2218{ 2219 register int i; 2220 2221 bzero((caddr_t)outcred, sizeof (struct ucred)); 2222 outcred->cr_ref = 1; 2223 outcred->cr_uid = incred->cr_uid; 2224 outcred->cr_ngroups = incred->cr_ngroups; 2225 for (i = 0; i < incred->cr_ngroups; i++) 2226 outcred->cr_groups[i] = incred->cr_groups[i]; 2227 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 2228} 2229#endif /* NFS_NOSERVER */ 2230