138420Smckusick /* 263485Sbostic * Copyright (c) 1989, 1993 363485Sbostic * The Regents of the University of California. All rights reserved. 438420Smckusick * 538420Smckusick * This code is derived from software contributed to Berkeley by 638420Smckusick * Rick Macklem at The University of Guelph. 738420Smckusick * 844513Sbostic * %sccs.include.redist.c% 938420Smckusick * 10*68653Smckusick * @(#)nfs_subs.c 8.6 (Berkeley) 03/30/95 1138420Smckusick */ 1238420Smckusick 13*68653Smckusick 1438420Smckusick /* 1538420Smckusick * These functions support the macros and help fiddle mbuf chains for 1638420Smckusick * the nfs op functions. They do things like create the rpc header and 1738420Smckusick * copy data between mbuf chains and uio lists. 1838420Smckusick */ 1953322Smckusick #include <sys/param.h> 2053322Smckusick #include <sys/proc.h> 2153322Smckusick #include <sys/systm.h> 2253322Smckusick #include <sys/kernel.h> 2353322Smckusick #include <sys/mount.h> 2453322Smckusick #include <sys/vnode.h> 2553322Smckusick #include <sys/namei.h> 2653322Smckusick #include <sys/mbuf.h> 2753322Smckusick #include <sys/socket.h> 2854445Smckusick #include <sys/stat.h> 29*68653Smckusick #include <sys/malloc.h> 30*68653Smckusick #ifdef VFS_LKM 31*68653Smckusick #include <sys/sysent.h> 32*68653Smckusick #include <sys/syscall.h> 33*68653Smckusick #endif 3447573Skarels 35*68653Smckusick #include <vm/vm.h> 36*68653Smckusick 3753322Smckusick #include <nfs/rpcv2.h> 38*68653Smckusick #include <nfs/nfsproto.h> 3953322Smckusick #include <nfs/nfsnode.h> 4053322Smckusick #include <nfs/nfs.h> 4153322Smckusick #include <nfs/xdr_subs.h> 4253322Smckusick #include <nfs/nfsm_subs.h> 4353322Smckusick #include <nfs/nfsmount.h> 4453322Smckusick #include <nfs/nqnfs.h> 4553322Smckusick #include <nfs/nfsrtt.h> 4653322Smckusick 4755703Smckusick #include <miscfs/specfs/specdev.h> 4855703Smckusick 4954988Smckusick #include <netinet/in.h> 5054988Smckusick #ifdef ISO 5154988Smckusick #include <netiso/iso.h> 5254988Smckusick #endif 5354988Smckusick 5438420Smckusick /* 5538420Smckusick * Data items converted to xdr at startup, since they are constant 5638420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 5738420Smckusick */ 5838420Smckusick u_long nfs_xdrneg1; 5952196Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 60*68653Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 6152196Smckusick rpc_auth_kerb; 62*68653Smckusick u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false; 6352196Smckusick 6438420Smckusick /* And other global data */ 6552196Smckusick static u_long nfs_xid = 0; 66*68653Smckusick enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 67*68653Smckusick enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 68*68653Smckusick int nfs_mount_type; 69*68653Smckusick int nfs_ticks; 70*68653Smckusick 71*68653Smckusick /* 72*68653Smckusick * Mapping of old NFS Version 2 RPC numbers to generic numbers. 73*68653Smckusick */ 74*68653Smckusick int nfsv3_procid[NFS_NPROCS] = { 75*68653Smckusick NFSPROC_NULL, 76*68653Smckusick NFSPROC_GETATTR, 77*68653Smckusick NFSPROC_SETATTR, 78*68653Smckusick NFSPROC_NOOP, 79*68653Smckusick NFSPROC_LOOKUP, 80*68653Smckusick NFSPROC_READLINK, 81*68653Smckusick NFSPROC_READ, 82*68653Smckusick NFSPROC_NOOP, 83*68653Smckusick NFSPROC_WRITE, 84*68653Smckusick NFSPROC_CREATE, 85*68653Smckusick NFSPROC_REMOVE, 86*68653Smckusick NFSPROC_RENAME, 87*68653Smckusick NFSPROC_LINK, 88*68653Smckusick NFSPROC_SYMLINK, 89*68653Smckusick NFSPROC_MKDIR, 90*68653Smckusick NFSPROC_RMDIR, 91*68653Smckusick NFSPROC_READDIR, 92*68653Smckusick NFSPROC_FSSTAT, 93*68653Smckusick NFSPROC_NOOP, 94*68653Smckusick NFSPROC_NOOP, 95*68653Smckusick NFSPROC_NOOP, 96*68653Smckusick NFSPROC_NOOP, 97*68653Smckusick NFSPROC_NOOP, 98*68653Smckusick NFSPROC_NOOP, 99*68653Smckusick NFSPROC_NOOP, 100*68653Smckusick NFSPROC_NOOP 101*68653Smckusick }; 102*68653Smckusick 103*68653Smckusick /* 104*68653Smckusick * and the reverse mapping from generic to Version 2 procedure numbers 105*68653Smckusick */ 106*68653Smckusick int nfsv2_procid[NFS_NPROCS] = { 107*68653Smckusick NFSV2PROC_NULL, 108*68653Smckusick NFSV2PROC_GETATTR, 109*68653Smckusick NFSV2PROC_SETATTR, 110*68653Smckusick NFSV2PROC_LOOKUP, 111*68653Smckusick NFSV2PROC_NOOP, 112*68653Smckusick NFSV2PROC_READLINK, 113*68653Smckusick NFSV2PROC_READ, 114*68653Smckusick NFSV2PROC_WRITE, 115*68653Smckusick NFSV2PROC_CREATE, 116*68653Smckusick NFSV2PROC_MKDIR, 117*68653Smckusick NFSV2PROC_SYMLINK, 118*68653Smckusick NFSV2PROC_CREATE, 119*68653Smckusick NFSV2PROC_REMOVE, 120*68653Smckusick NFSV2PROC_RMDIR, 121*68653Smckusick NFSV2PROC_RENAME, 122*68653Smckusick NFSV2PROC_LINK, 123*68653Smckusick NFSV2PROC_READDIR, 124*68653Smckusick NFSV2PROC_NOOP, 125*68653Smckusick NFSV2PROC_STATFS, 126*68653Smckusick NFSV2PROC_NOOP, 127*68653Smckusick NFSV2PROC_NOOP, 128*68653Smckusick NFSV2PROC_NOOP, 129*68653Smckusick NFSV2PROC_NOOP, 130*68653Smckusick NFSV2PROC_NOOP, 131*68653Smckusick NFSV2PROC_NOOP, 132*68653Smckusick NFSV2PROC_NOOP, 133*68653Smckusick }; 134*68653Smckusick 135*68653Smckusick /* 136*68653Smckusick * Maps errno values to nfs error numbers. 137*68653Smckusick * Use NFSERR_IO as the catch all for ones not specifically defined in 138*68653Smckusick * RFC 1094. 139*68653Smckusick */ 140*68653Smckusick static u_char nfsrv_v2errmap[ELAST] = { 141*68653Smckusick NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 142*68653Smckusick NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 143*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 144*68653Smckusick NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 145*68653Smckusick NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 146*68653Smckusick NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 147*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 148*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 149*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 150*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 151*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 152*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 153*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 154*68653Smckusick NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 155*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 156*68653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 157*68653Smckusick NFSERR_IO, 158*68653Smckusick }; 159*68653Smckusick 160*68653Smckusick /* 161*68653Smckusick * Maps errno values to nfs error numbers. 162*68653Smckusick * Although it is not obvious whether or not NFS clients really care if 163*68653Smckusick * a returned error value is in the specified list for the procedure, the 164*68653Smckusick * safest thing to do is filter them appropriately. For Version 2, the 165*68653Smckusick * X/Open XNFS document is the only specification that defines error values 166*68653Smckusick * for each RPC (The RFC simply lists all possible error values for all RPCs), 167*68653Smckusick * so I have decided to not do this for Version 2. 168*68653Smckusick * The first entry is the default error return and the rest are the valid 169*68653Smckusick * errors for that RPC in increasing numeric order. 170*68653Smckusick */ 171*68653Smckusick static short nfsv3err_null[] = { 172*68653Smckusick 0, 173*68653Smckusick 0, 174*68653Smckusick }; 175*68653Smckusick 176*68653Smckusick static short nfsv3err_getattr[] = { 177*68653Smckusick NFSERR_IO, 178*68653Smckusick NFSERR_IO, 179*68653Smckusick NFSERR_STALE, 180*68653Smckusick NFSERR_BADHANDLE, 181*68653Smckusick NFSERR_SERVERFAULT, 182*68653Smckusick 0, 183*68653Smckusick }; 184*68653Smckusick 185*68653Smckusick static short nfsv3err_setattr[] = { 186*68653Smckusick NFSERR_IO, 187*68653Smckusick NFSERR_PERM, 188*68653Smckusick NFSERR_IO, 189*68653Smckusick NFSERR_ACCES, 190*68653Smckusick NFSERR_INVAL, 191*68653Smckusick NFSERR_NOSPC, 192*68653Smckusick NFSERR_ROFS, 193*68653Smckusick NFSERR_DQUOT, 194*68653Smckusick NFSERR_STALE, 195*68653Smckusick NFSERR_BADHANDLE, 196*68653Smckusick NFSERR_NOT_SYNC, 197*68653Smckusick NFSERR_SERVERFAULT, 198*68653Smckusick 0, 199*68653Smckusick }; 200*68653Smckusick 201*68653Smckusick static short nfsv3err_lookup[] = { 202*68653Smckusick NFSERR_IO, 203*68653Smckusick NFSERR_NOENT, 204*68653Smckusick NFSERR_IO, 205*68653Smckusick NFSERR_ACCES, 206*68653Smckusick NFSERR_NOTDIR, 207*68653Smckusick NFSERR_NAMETOL, 208*68653Smckusick NFSERR_STALE, 209*68653Smckusick NFSERR_BADHANDLE, 210*68653Smckusick NFSERR_SERVERFAULT, 211*68653Smckusick 0, 212*68653Smckusick }; 213*68653Smckusick 214*68653Smckusick static short nfsv3err_access[] = { 215*68653Smckusick NFSERR_IO, 216*68653Smckusick NFSERR_IO, 217*68653Smckusick NFSERR_STALE, 218*68653Smckusick NFSERR_BADHANDLE, 219*68653Smckusick NFSERR_SERVERFAULT, 220*68653Smckusick 0, 221*68653Smckusick }; 222*68653Smckusick 223*68653Smckusick static short nfsv3err_readlink[] = { 224*68653Smckusick NFSERR_IO, 225*68653Smckusick NFSERR_IO, 226*68653Smckusick NFSERR_ACCES, 227*68653Smckusick NFSERR_INVAL, 228*68653Smckusick NFSERR_STALE, 229*68653Smckusick NFSERR_BADHANDLE, 230*68653Smckusick NFSERR_NOTSUPP, 231*68653Smckusick NFSERR_SERVERFAULT, 232*68653Smckusick 0, 233*68653Smckusick }; 234*68653Smckusick 235*68653Smckusick static short nfsv3err_read[] = { 236*68653Smckusick NFSERR_IO, 237*68653Smckusick NFSERR_IO, 238*68653Smckusick NFSERR_NXIO, 239*68653Smckusick NFSERR_ACCES, 240*68653Smckusick NFSERR_INVAL, 241*68653Smckusick NFSERR_STALE, 242*68653Smckusick NFSERR_BADHANDLE, 243*68653Smckusick NFSERR_SERVERFAULT, 244*68653Smckusick 0, 245*68653Smckusick }; 246*68653Smckusick 247*68653Smckusick static short nfsv3err_write[] = { 248*68653Smckusick NFSERR_IO, 249*68653Smckusick NFSERR_IO, 250*68653Smckusick NFSERR_ACCES, 251*68653Smckusick NFSERR_INVAL, 252*68653Smckusick NFSERR_FBIG, 253*68653Smckusick NFSERR_NOSPC, 254*68653Smckusick NFSERR_ROFS, 255*68653Smckusick NFSERR_DQUOT, 256*68653Smckusick NFSERR_STALE, 257*68653Smckusick NFSERR_BADHANDLE, 258*68653Smckusick NFSERR_SERVERFAULT, 259*68653Smckusick 0, 260*68653Smckusick }; 261*68653Smckusick 262*68653Smckusick static short nfsv3err_create[] = { 263*68653Smckusick NFSERR_IO, 264*68653Smckusick NFSERR_IO, 265*68653Smckusick NFSERR_ACCES, 266*68653Smckusick NFSERR_EXIST, 267*68653Smckusick NFSERR_NOTDIR, 268*68653Smckusick NFSERR_NOSPC, 269*68653Smckusick NFSERR_ROFS, 270*68653Smckusick NFSERR_NAMETOL, 271*68653Smckusick NFSERR_DQUOT, 272*68653Smckusick NFSERR_STALE, 273*68653Smckusick NFSERR_BADHANDLE, 274*68653Smckusick NFSERR_NOTSUPP, 275*68653Smckusick NFSERR_SERVERFAULT, 276*68653Smckusick 0, 277*68653Smckusick }; 278*68653Smckusick 279*68653Smckusick static short nfsv3err_mkdir[] = { 280*68653Smckusick NFSERR_IO, 281*68653Smckusick NFSERR_IO, 282*68653Smckusick NFSERR_ACCES, 283*68653Smckusick NFSERR_EXIST, 284*68653Smckusick NFSERR_NOTDIR, 285*68653Smckusick NFSERR_NOSPC, 286*68653Smckusick NFSERR_ROFS, 287*68653Smckusick NFSERR_NAMETOL, 288*68653Smckusick NFSERR_DQUOT, 289*68653Smckusick NFSERR_STALE, 290*68653Smckusick NFSERR_BADHANDLE, 291*68653Smckusick NFSERR_NOTSUPP, 292*68653Smckusick NFSERR_SERVERFAULT, 293*68653Smckusick 0, 294*68653Smckusick }; 295*68653Smckusick 296*68653Smckusick static short nfsv3err_symlink[] = { 297*68653Smckusick NFSERR_IO, 298*68653Smckusick NFSERR_IO, 299*68653Smckusick NFSERR_ACCES, 300*68653Smckusick NFSERR_EXIST, 301*68653Smckusick NFSERR_NOTDIR, 302*68653Smckusick NFSERR_NOSPC, 303*68653Smckusick NFSERR_ROFS, 304*68653Smckusick NFSERR_NAMETOL, 305*68653Smckusick NFSERR_DQUOT, 306*68653Smckusick NFSERR_STALE, 307*68653Smckusick NFSERR_BADHANDLE, 308*68653Smckusick NFSERR_NOTSUPP, 309*68653Smckusick NFSERR_SERVERFAULT, 310*68653Smckusick 0, 311*68653Smckusick }; 312*68653Smckusick 313*68653Smckusick static short nfsv3err_mknod[] = { 314*68653Smckusick NFSERR_IO, 315*68653Smckusick NFSERR_IO, 316*68653Smckusick NFSERR_ACCES, 317*68653Smckusick NFSERR_EXIST, 318*68653Smckusick NFSERR_NOTDIR, 319*68653Smckusick NFSERR_NOSPC, 320*68653Smckusick NFSERR_ROFS, 321*68653Smckusick NFSERR_NAMETOL, 322*68653Smckusick NFSERR_DQUOT, 323*68653Smckusick NFSERR_STALE, 324*68653Smckusick NFSERR_BADHANDLE, 325*68653Smckusick NFSERR_NOTSUPP, 326*68653Smckusick NFSERR_SERVERFAULT, 327*68653Smckusick NFSERR_BADTYPE, 328*68653Smckusick 0, 329*68653Smckusick }; 330*68653Smckusick 331*68653Smckusick static short nfsv3err_remove[] = { 332*68653Smckusick NFSERR_IO, 333*68653Smckusick NFSERR_NOENT, 334*68653Smckusick NFSERR_IO, 335*68653Smckusick NFSERR_ACCES, 336*68653Smckusick NFSERR_NOTDIR, 337*68653Smckusick NFSERR_ROFS, 338*68653Smckusick NFSERR_NAMETOL, 339*68653Smckusick NFSERR_STALE, 340*68653Smckusick NFSERR_BADHANDLE, 341*68653Smckusick NFSERR_SERVERFAULT, 342*68653Smckusick 0, 343*68653Smckusick }; 344*68653Smckusick 345*68653Smckusick static short nfsv3err_rmdir[] = { 346*68653Smckusick NFSERR_IO, 347*68653Smckusick NFSERR_NOENT, 348*68653Smckusick NFSERR_IO, 349*68653Smckusick NFSERR_ACCES, 350*68653Smckusick NFSERR_EXIST, 351*68653Smckusick NFSERR_NOTDIR, 352*68653Smckusick NFSERR_INVAL, 353*68653Smckusick NFSERR_ROFS, 354*68653Smckusick NFSERR_NAMETOL, 355*68653Smckusick NFSERR_NOTEMPTY, 356*68653Smckusick NFSERR_STALE, 357*68653Smckusick NFSERR_BADHANDLE, 358*68653Smckusick NFSERR_NOTSUPP, 359*68653Smckusick NFSERR_SERVERFAULT, 360*68653Smckusick 0, 361*68653Smckusick }; 362*68653Smckusick 363*68653Smckusick static short nfsv3err_rename[] = { 364*68653Smckusick NFSERR_IO, 365*68653Smckusick NFSERR_NOENT, 366*68653Smckusick NFSERR_IO, 367*68653Smckusick NFSERR_ACCES, 368*68653Smckusick NFSERR_EXIST, 369*68653Smckusick NFSERR_XDEV, 370*68653Smckusick NFSERR_NOTDIR, 371*68653Smckusick NFSERR_ISDIR, 372*68653Smckusick NFSERR_INVAL, 373*68653Smckusick NFSERR_NOSPC, 374*68653Smckusick NFSERR_ROFS, 375*68653Smckusick NFSERR_MLINK, 376*68653Smckusick NFSERR_NAMETOL, 377*68653Smckusick NFSERR_NOTEMPTY, 378*68653Smckusick NFSERR_DQUOT, 379*68653Smckusick NFSERR_STALE, 380*68653Smckusick NFSERR_BADHANDLE, 381*68653Smckusick NFSERR_NOTSUPP, 382*68653Smckusick NFSERR_SERVERFAULT, 383*68653Smckusick 0, 384*68653Smckusick }; 385*68653Smckusick 386*68653Smckusick static short nfsv3err_link[] = { 387*68653Smckusick NFSERR_IO, 388*68653Smckusick NFSERR_IO, 389*68653Smckusick NFSERR_ACCES, 390*68653Smckusick NFSERR_EXIST, 391*68653Smckusick NFSERR_XDEV, 392*68653Smckusick NFSERR_NOTDIR, 393*68653Smckusick NFSERR_INVAL, 394*68653Smckusick NFSERR_NOSPC, 395*68653Smckusick NFSERR_ROFS, 396*68653Smckusick NFSERR_MLINK, 397*68653Smckusick NFSERR_NAMETOL, 398*68653Smckusick NFSERR_DQUOT, 399*68653Smckusick NFSERR_STALE, 400*68653Smckusick NFSERR_BADHANDLE, 401*68653Smckusick NFSERR_NOTSUPP, 402*68653Smckusick NFSERR_SERVERFAULT, 403*68653Smckusick 0, 404*68653Smckusick }; 405*68653Smckusick 406*68653Smckusick static short nfsv3err_readdir[] = { 407*68653Smckusick NFSERR_IO, 408*68653Smckusick NFSERR_IO, 409*68653Smckusick NFSERR_ACCES, 410*68653Smckusick NFSERR_NOTDIR, 411*68653Smckusick NFSERR_STALE, 412*68653Smckusick NFSERR_BADHANDLE, 413*68653Smckusick NFSERR_BAD_COOKIE, 414*68653Smckusick NFSERR_TOOSMALL, 415*68653Smckusick NFSERR_SERVERFAULT, 416*68653Smckusick 0, 417*68653Smckusick }; 418*68653Smckusick 419*68653Smckusick static short nfsv3err_readdirplus[] = { 420*68653Smckusick NFSERR_IO, 421*68653Smckusick NFSERR_IO, 422*68653Smckusick NFSERR_ACCES, 423*68653Smckusick NFSERR_NOTDIR, 424*68653Smckusick NFSERR_STALE, 425*68653Smckusick NFSERR_BADHANDLE, 426*68653Smckusick NFSERR_BAD_COOKIE, 427*68653Smckusick NFSERR_NOTSUPP, 428*68653Smckusick NFSERR_TOOSMALL, 429*68653Smckusick NFSERR_SERVERFAULT, 430*68653Smckusick 0, 431*68653Smckusick }; 432*68653Smckusick 433*68653Smckusick static short nfsv3err_fsstat[] = { 434*68653Smckusick NFSERR_IO, 435*68653Smckusick NFSERR_IO, 436*68653Smckusick NFSERR_STALE, 437*68653Smckusick NFSERR_BADHANDLE, 438*68653Smckusick NFSERR_SERVERFAULT, 439*68653Smckusick 0, 440*68653Smckusick }; 441*68653Smckusick 442*68653Smckusick static short nfsv3err_fsinfo[] = { 443*68653Smckusick NFSERR_STALE, 444*68653Smckusick NFSERR_STALE, 445*68653Smckusick NFSERR_BADHANDLE, 446*68653Smckusick NFSERR_SERVERFAULT, 447*68653Smckusick 0, 448*68653Smckusick }; 449*68653Smckusick 450*68653Smckusick static short nfsv3err_pathconf[] = { 451*68653Smckusick NFSERR_STALE, 452*68653Smckusick NFSERR_STALE, 453*68653Smckusick NFSERR_BADHANDLE, 454*68653Smckusick NFSERR_SERVERFAULT, 455*68653Smckusick 0, 456*68653Smckusick }; 457*68653Smckusick 458*68653Smckusick static short nfsv3err_commit[] = { 459*68653Smckusick NFSERR_IO, 460*68653Smckusick NFSERR_IO, 461*68653Smckusick NFSERR_STALE, 462*68653Smckusick NFSERR_BADHANDLE, 463*68653Smckusick NFSERR_SERVERFAULT, 464*68653Smckusick 0, 465*68653Smckusick }; 466*68653Smckusick 467*68653Smckusick static short *nfsrv_v3errmap[] = { 468*68653Smckusick nfsv3err_null, 469*68653Smckusick nfsv3err_getattr, 470*68653Smckusick nfsv3err_setattr, 471*68653Smckusick nfsv3err_lookup, 472*68653Smckusick nfsv3err_access, 473*68653Smckusick nfsv3err_readlink, 474*68653Smckusick nfsv3err_read, 475*68653Smckusick nfsv3err_write, 476*68653Smckusick nfsv3err_create, 477*68653Smckusick nfsv3err_mkdir, 478*68653Smckusick nfsv3err_symlink, 479*68653Smckusick nfsv3err_mknod, 480*68653Smckusick nfsv3err_remove, 481*68653Smckusick nfsv3err_rmdir, 482*68653Smckusick nfsv3err_rename, 483*68653Smckusick nfsv3err_link, 484*68653Smckusick nfsv3err_readdir, 485*68653Smckusick nfsv3err_readdirplus, 486*68653Smckusick nfsv3err_fsstat, 487*68653Smckusick nfsv3err_fsinfo, 488*68653Smckusick nfsv3err_pathconf, 489*68653Smckusick nfsv3err_commit, 490*68653Smckusick }; 491*68653Smckusick 49241902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 49352196Smckusick extern struct nfsrtt nfsrtt; 49452196Smckusick extern time_t nqnfsstarttime; 49552196Smckusick extern int nqsrv_clockskew; 49652196Smckusick extern int nqsrv_writeslack; 49752196Smckusick extern int nqsrv_maxlease; 498*68653Smckusick extern struct nfsstats nfsstats; 499*68653Smckusick extern int nqnfs_piggy[NFS_NPROCS]; 500*68653Smckusick extern nfstype nfsv2_type[9]; 501*68653Smckusick extern nfstype nfsv3_type[9]; 502*68653Smckusick extern struct nfsnodehashhead *nfsnodehashtbl; 503*68653Smckusick extern u_long nfsnodehash; 50438420Smckusick 505*68653Smckusick #ifdef VFS_LKM 506*68653Smckusick struct getfh_args; 507*68653Smckusick extern int getfh(struct proc *, struct getfh_args *, int *); 508*68653Smckusick struct nfssvc_args; 509*68653Smckusick extern int nfssvc(struct proc *, struct nfssvc_args *, int *); 510*68653Smckusick #endif 511*68653Smckusick 51267708Smckusick LIST_HEAD(nfsnodehashhead, nfsnode); 51367708Smckusick 51438420Smckusick /* 51538420Smckusick * Create the header for an rpc request packet 51638420Smckusick * The hsiz is the size of the rest of the nfs request header. 51738420Smckusick * (just used to decide if a cluster is a good idea) 51838420Smckusick */ 51952196Smckusick struct mbuf * 52052196Smckusick nfsm_reqh(vp, procid, hsiz, bposp) 52152196Smckusick struct vnode *vp; 52239494Smckusick u_long procid; 52338420Smckusick int hsiz; 52452196Smckusick caddr_t *bposp; 52538420Smckusick { 52652196Smckusick register struct mbuf *mb; 52748049Smckusick register u_long *tl; 52852196Smckusick register caddr_t bpos; 52952196Smckusick struct mbuf *mb2; 53052196Smckusick struct nfsmount *nmp; 53152196Smckusick int nqflag; 53238420Smckusick 53352196Smckusick MGET(mb, M_WAIT, MT_DATA); 53452196Smckusick if (hsiz >= MINCLSIZE) 53552196Smckusick MCLGET(mb, M_WAIT); 53652196Smckusick mb->m_len = 0; 53752196Smckusick bpos = mtod(mb, caddr_t); 53852196Smckusick 53952196Smckusick /* 54052196Smckusick * For NQNFS, add lease request. 54152196Smckusick */ 54252196Smckusick if (vp) { 54352196Smckusick nmp = VFSTONFS(vp->v_mount); 54452196Smckusick if (nmp->nm_flag & NFSMNT_NQNFS) { 54552196Smckusick nqflag = NQNFS_NEEDLEASE(vp, procid); 54652196Smckusick if (nqflag) { 54752196Smckusick nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 54852196Smckusick *tl++ = txdr_unsigned(nqflag); 54952196Smckusick *tl = txdr_unsigned(nmp->nm_leaseterm); 55052196Smckusick } else { 55152196Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 55252196Smckusick *tl = 0; 55352196Smckusick } 55452196Smckusick } 55552196Smckusick } 55652196Smckusick /* Finally, return values */ 55752196Smckusick *bposp = bpos; 55852196Smckusick return (mb); 55952196Smckusick } 56038420Smckusick 56152196Smckusick /* 56252196Smckusick * Build the RPC header and fill in the authorization info. 56352196Smckusick * The authorization string argument is only used when the credentials 56452196Smckusick * come from outside of the kernel. 56552196Smckusick * Returns the head of the mbuf list. 56652196Smckusick */ 56752196Smckusick struct mbuf * 568*68653Smckusick nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 569*68653Smckusick verf_str, mrest, mrest_len, mbp, xidp) 57052196Smckusick register struct ucred *cr; 571*68653Smckusick int nmflag; 57252196Smckusick int procid; 57352196Smckusick int auth_type; 57452196Smckusick int auth_len; 57552196Smckusick char *auth_str; 576*68653Smckusick int verf_len; 577*68653Smckusick char *verf_str; 57852196Smckusick struct mbuf *mrest; 57952196Smckusick int mrest_len; 58052196Smckusick struct mbuf **mbp; 58152196Smckusick u_long *xidp; 58252196Smckusick { 58352196Smckusick register struct mbuf *mb; 58452196Smckusick register u_long *tl; 58552196Smckusick register caddr_t bpos; 58652196Smckusick register int i; 58752196Smckusick struct mbuf *mreq, *mb2; 58852196Smckusick int siz, grpsiz, authsiz; 58952196Smckusick 59052196Smckusick authsiz = nfsm_rndup(auth_len); 59152196Smckusick MGETHDR(mb, M_WAIT, MT_DATA); 592*68653Smckusick if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 59352196Smckusick MCLGET(mb, M_WAIT); 594*68653Smckusick } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 595*68653Smckusick MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 59652196Smckusick } else { 597*68653Smckusick MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 59852196Smckusick } 59952196Smckusick mb->m_len = 0; 60052196Smckusick mreq = mb; 60152196Smckusick bpos = mtod(mb, caddr_t); 60252196Smckusick 60338420Smckusick /* 60452196Smckusick * First the RPC header. 60538420Smckusick */ 606*68653Smckusick nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED); 60752196Smckusick if (++nfs_xid == 0) 60852196Smckusick nfs_xid++; 60952196Smckusick *tl++ = *xidp = txdr_unsigned(nfs_xid); 61048049Smckusick *tl++ = rpc_call; 61148049Smckusick *tl++ = rpc_vers; 612*68653Smckusick if (nmflag & NFSMNT_NQNFS) { 61352196Smckusick *tl++ = txdr_unsigned(NQNFS_PROG); 614*68653Smckusick *tl++ = txdr_unsigned(NQNFS_VER3); 61552196Smckusick } else { 61652196Smckusick *tl++ = txdr_unsigned(NFS_PROG); 617*68653Smckusick if (nmflag & NFSMNT_NFSV3) 618*68653Smckusick *tl++ = txdr_unsigned(NFS_VER3); 619*68653Smckusick else 620*68653Smckusick *tl++ = txdr_unsigned(NFS_VER2); 62152196Smckusick } 622*68653Smckusick if (nmflag & NFSMNT_NFSV3) 623*68653Smckusick *tl++ = txdr_unsigned(procid); 624*68653Smckusick else 625*68653Smckusick *tl++ = txdr_unsigned(nfsv2_procid[procid]); 62638420Smckusick 62752196Smckusick /* 62852196Smckusick * And then the authorization cred. 62952196Smckusick */ 63052196Smckusick *tl++ = txdr_unsigned(auth_type); 63152196Smckusick *tl = txdr_unsigned(authsiz); 63252196Smckusick switch (auth_type) { 63352196Smckusick case RPCAUTH_UNIX: 63452196Smckusick nfsm_build(tl, u_long *, auth_len); 63552196Smckusick *tl++ = 0; /* stamp ?? */ 63652196Smckusick *tl++ = 0; /* NULL hostname */ 63752196Smckusick *tl++ = txdr_unsigned(cr->cr_uid); 63852196Smckusick *tl++ = txdr_unsigned(cr->cr_groups[0]); 63952196Smckusick grpsiz = (auth_len >> 2) - 5; 64052196Smckusick *tl++ = txdr_unsigned(grpsiz); 64152196Smckusick for (i = 1; i <= grpsiz; i++) 64252196Smckusick *tl++ = txdr_unsigned(cr->cr_groups[i]); 64352196Smckusick break; 644*68653Smckusick case RPCAUTH_KERB4: 64552196Smckusick siz = auth_len; 64652196Smckusick while (siz > 0) { 64752196Smckusick if (M_TRAILINGSPACE(mb) == 0) { 64852196Smckusick MGET(mb2, M_WAIT, MT_DATA); 64952196Smckusick if (siz >= MINCLSIZE) 65052196Smckusick MCLGET(mb2, M_WAIT); 65152196Smckusick mb->m_next = mb2; 65252196Smckusick mb = mb2; 65352196Smckusick mb->m_len = 0; 65452196Smckusick bpos = mtod(mb, caddr_t); 65552196Smckusick } 65655057Spendry i = min(siz, M_TRAILINGSPACE(mb)); 65752196Smckusick bcopy(auth_str, bpos, i); 65852196Smckusick mb->m_len += i; 65952196Smckusick auth_str += i; 66052196Smckusick bpos += i; 66152196Smckusick siz -= i; 66238420Smckusick } 66357787Smckusick if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 66452196Smckusick for (i = 0; i < siz; i++) 66552196Smckusick *bpos++ = '\0'; 66652196Smckusick mb->m_len += siz; 66752196Smckusick } 66852196Smckusick break; 66952196Smckusick }; 670*68653Smckusick 671*68653Smckusick /* 672*68653Smckusick * And the verifier... 673*68653Smckusick */ 674*68653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); 675*68653Smckusick if (verf_str) { 676*68653Smckusick *tl++ = txdr_unsigned(RPCAUTH_KERB4); 677*68653Smckusick *tl = txdr_unsigned(verf_len); 678*68653Smckusick siz = verf_len; 679*68653Smckusick while (siz > 0) { 680*68653Smckusick if (M_TRAILINGSPACE(mb) == 0) { 681*68653Smckusick MGET(mb2, M_WAIT, MT_DATA); 682*68653Smckusick if (siz >= MINCLSIZE) 683*68653Smckusick MCLGET(mb2, M_WAIT); 684*68653Smckusick mb->m_next = mb2; 685*68653Smckusick mb = mb2; 686*68653Smckusick mb->m_len = 0; 687*68653Smckusick bpos = mtod(mb, caddr_t); 688*68653Smckusick } 689*68653Smckusick i = min(siz, M_TRAILINGSPACE(mb)); 690*68653Smckusick bcopy(verf_str, bpos, i); 691*68653Smckusick mb->m_len += i; 692*68653Smckusick verf_str += i; 693*68653Smckusick bpos += i; 694*68653Smckusick siz -= i; 695*68653Smckusick } 696*68653Smckusick if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 697*68653Smckusick for (i = 0; i < siz; i++) 698*68653Smckusick *bpos++ = '\0'; 699*68653Smckusick mb->m_len += siz; 700*68653Smckusick } 701*68653Smckusick } else { 702*68653Smckusick *tl++ = txdr_unsigned(RPCAUTH_NULL); 703*68653Smckusick *tl = 0; 704*68653Smckusick } 70552196Smckusick mb->m_next = mrest; 706*68653Smckusick mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 70752196Smckusick mreq->m_pkthdr.rcvif = (struct ifnet *)0; 70852196Smckusick *mbp = mb; 70938420Smckusick return (mreq); 71038420Smckusick } 71138420Smckusick 71238420Smckusick /* 71338420Smckusick * copies mbuf chain to the uio scatter/gather list 71438420Smckusick */ 715*68653Smckusick int 71638420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 71738420Smckusick struct mbuf **mrep; 71843353Smckusick register struct uio *uiop; 71938420Smckusick int siz; 72038420Smckusick caddr_t *dpos; 72138420Smckusick { 72243353Smckusick register char *mbufcp, *uiocp; 72338420Smckusick register int xfer, left, len; 72438420Smckusick register struct mbuf *mp; 72538420Smckusick long uiosiz, rem; 72641902Smckusick int error = 0; 72738420Smckusick 72838420Smckusick mp = *mrep; 72938420Smckusick mbufcp = *dpos; 73038420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 73138420Smckusick rem = nfsm_rndup(siz)-siz; 73238420Smckusick while (siz > 0) { 73338420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 73441902Smckusick return (EFBIG); 73538420Smckusick left = uiop->uio_iov->iov_len; 73638420Smckusick uiocp = uiop->uio_iov->iov_base; 73738420Smckusick if (left > siz) 73838420Smckusick left = siz; 73938420Smckusick uiosiz = left; 74038420Smckusick while (left > 0) { 74138420Smckusick while (len == 0) { 74238420Smckusick mp = mp->m_next; 74338420Smckusick if (mp == NULL) 74438420Smckusick return (EBADRPC); 74538420Smckusick mbufcp = mtod(mp, caddr_t); 74638420Smckusick len = mp->m_len; 74738420Smckusick } 74838420Smckusick xfer = (left > len) ? len : left; 74938420Smckusick #ifdef notdef 75038420Smckusick /* Not Yet.. */ 75138420Smckusick if (uiop->uio_iov->iov_op != NULL) 75238420Smckusick (*(uiop->uio_iov->iov_op)) 75338420Smckusick (mbufcp, uiocp, xfer); 75438420Smckusick else 75538420Smckusick #endif 75638420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 75738420Smckusick bcopy(mbufcp, uiocp, xfer); 75838420Smckusick else 75938420Smckusick copyout(mbufcp, uiocp, xfer); 76038420Smckusick left -= xfer; 76138420Smckusick len -= xfer; 76238420Smckusick mbufcp += xfer; 76338420Smckusick uiocp += xfer; 76439585Smckusick uiop->uio_offset += xfer; 76538420Smckusick uiop->uio_resid -= xfer; 76638420Smckusick } 76738420Smckusick if (uiop->uio_iov->iov_len <= siz) { 76838420Smckusick uiop->uio_iovcnt--; 76938420Smckusick uiop->uio_iov++; 77038420Smckusick } else { 77138420Smckusick uiop->uio_iov->iov_base += uiosiz; 77238420Smckusick uiop->uio_iov->iov_len -= uiosiz; 77338420Smckusick } 77438420Smckusick siz -= uiosiz; 77538420Smckusick } 77638420Smckusick *dpos = mbufcp; 77738420Smckusick *mrep = mp; 77841902Smckusick if (rem > 0) { 77941902Smckusick if (len < rem) 78041902Smckusick error = nfs_adv(mrep, dpos, rem, len); 78141902Smckusick else 78241902Smckusick *dpos += rem; 78341902Smckusick } 78441902Smckusick return (error); 78538420Smckusick } 78638420Smckusick 78738420Smckusick /* 78838420Smckusick * copies a uio scatter/gather list to an mbuf chain... 78938420Smckusick */ 790*68653Smckusick int 79138420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 79238420Smckusick register struct uio *uiop; 79338420Smckusick struct mbuf **mq; 79438420Smckusick int siz; 79538420Smckusick caddr_t *bpos; 79638420Smckusick { 79743353Smckusick register char *uiocp; 79843353Smckusick register struct mbuf *mp, *mp2; 79952196Smckusick register int xfer, left, mlen; 80043353Smckusick int uiosiz, clflg, rem; 80143353Smckusick char *cp; 80238420Smckusick 80338420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 80438420Smckusick clflg = 1; 80538420Smckusick else 80638420Smckusick clflg = 0; 80738420Smckusick rem = nfsm_rndup(siz)-siz; 80852196Smckusick mp = mp2 = *mq; 80938420Smckusick while (siz > 0) { 81038420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 81141902Smckusick return (EINVAL); 81238420Smckusick left = uiop->uio_iov->iov_len; 81338420Smckusick uiocp = uiop->uio_iov->iov_base; 81438420Smckusick if (left > siz) 81538420Smckusick left = siz; 81638420Smckusick uiosiz = left; 81738420Smckusick while (left > 0) { 81852196Smckusick mlen = M_TRAILINGSPACE(mp); 81952196Smckusick if (mlen == 0) { 82052196Smckusick MGET(mp, M_WAIT, MT_DATA); 82152196Smckusick if (clflg) 82252196Smckusick MCLGET(mp, M_WAIT); 82352196Smckusick mp->m_len = 0; 82452196Smckusick mp2->m_next = mp; 82552196Smckusick mp2 = mp; 82652196Smckusick mlen = M_TRAILINGSPACE(mp); 82752196Smckusick } 82852196Smckusick xfer = (left > mlen) ? mlen : left; 82938420Smckusick #ifdef notdef 83038420Smckusick /* Not Yet.. */ 83138420Smckusick if (uiop->uio_iov->iov_op != NULL) 83238420Smckusick (*(uiop->uio_iov->iov_op)) 83352196Smckusick (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 83438420Smckusick else 83538420Smckusick #endif 83638420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 83752196Smckusick bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 83838420Smckusick else 83952196Smckusick copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 84052196Smckusick mp->m_len += xfer; 84138420Smckusick left -= xfer; 84238420Smckusick uiocp += xfer; 84339585Smckusick uiop->uio_offset += xfer; 84438420Smckusick uiop->uio_resid -= xfer; 84538420Smckusick } 84638420Smckusick if (uiop->uio_iov->iov_len <= siz) { 84738420Smckusick uiop->uio_iovcnt--; 84838420Smckusick uiop->uio_iov++; 84938420Smckusick } else { 85038420Smckusick uiop->uio_iov->iov_base += uiosiz; 85138420Smckusick uiop->uio_iov->iov_len -= uiosiz; 85238420Smckusick } 85338420Smckusick siz -= uiosiz; 85438420Smckusick } 85538420Smckusick if (rem > 0) { 85652196Smckusick if (rem > M_TRAILINGSPACE(mp)) { 85738420Smckusick MGET(mp, M_WAIT, MT_DATA); 85838420Smckusick mp->m_len = 0; 85938420Smckusick mp2->m_next = mp; 86038420Smckusick } 86138420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 86238420Smckusick for (left = 0; left < rem; left++) 86338420Smckusick *cp++ = '\0'; 86438420Smckusick mp->m_len += rem; 86538420Smckusick *bpos = cp; 86638420Smckusick } else 86738420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 86838420Smckusick *mq = mp; 86941902Smckusick return (0); 87038420Smckusick } 87138420Smckusick 87238420Smckusick /* 87338420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 87438420Smckusick * pointed to by returned val. 87552196Smckusick * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 87638420Smckusick * cases. (The macros use the vars. dpos and dpos2) 87738420Smckusick */ 878*68653Smckusick int 87963482Smckusick nfsm_disct(mdp, dposp, siz, left, cp2) 88038420Smckusick struct mbuf **mdp; 88138420Smckusick caddr_t *dposp; 88238420Smckusick int siz; 88338420Smckusick int left; 88438420Smckusick caddr_t *cp2; 88538420Smckusick { 88638420Smckusick register struct mbuf *mp, *mp2; 88738420Smckusick register int siz2, xfer; 88852196Smckusick register caddr_t p; 88938420Smckusick 89038420Smckusick mp = *mdp; 89138420Smckusick while (left == 0) { 89238420Smckusick *mdp = mp = mp->m_next; 89338420Smckusick if (mp == NULL) 89441902Smckusick return (EBADRPC); 89538420Smckusick left = mp->m_len; 89638420Smckusick *dposp = mtod(mp, caddr_t); 89738420Smckusick } 89838420Smckusick if (left >= siz) { 89938420Smckusick *cp2 = *dposp; 90038420Smckusick *dposp += siz; 90138420Smckusick } else if (mp->m_next == NULL) { 90241902Smckusick return (EBADRPC); 90341902Smckusick } else if (siz > MHLEN) { 90438420Smckusick panic("nfs S too big"); 90538420Smckusick } else { 90663482Smckusick MGET(mp2, M_WAIT, MT_DATA); 90763482Smckusick mp2->m_next = mp->m_next; 90863482Smckusick mp->m_next = mp2; 90963482Smckusick mp->m_len -= left; 91063482Smckusick mp = mp2; 91152196Smckusick *cp2 = p = mtod(mp, caddr_t); 91252196Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 91338420Smckusick siz2 = siz-left; 91452196Smckusick p += left; 91538420Smckusick mp2 = mp->m_next; 91641902Smckusick /* Loop around copying up the siz2 bytes */ 91738420Smckusick while (siz2 > 0) { 91838420Smckusick if (mp2 == NULL) 91938420Smckusick return (EBADRPC); 92038420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 92141902Smckusick if (xfer > 0) { 92252196Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 92341902Smckusick NFSMADV(mp2, xfer); 92441902Smckusick mp2->m_len -= xfer; 92552196Smckusick p += xfer; 92641902Smckusick siz2 -= xfer; 92741902Smckusick } 92838420Smckusick if (siz2 > 0) 92938420Smckusick mp2 = mp2->m_next; 93038420Smckusick } 93138420Smckusick mp->m_len = siz; 93238420Smckusick *mdp = mp2; 93338420Smckusick *dposp = mtod(mp2, caddr_t); 93438420Smckusick } 93539494Smckusick return (0); 93638420Smckusick } 93738420Smckusick 93838420Smckusick /* 93941902Smckusick * Advance the position in the mbuf chain. 94038420Smckusick */ 941*68653Smckusick int 94238420Smckusick nfs_adv(mdp, dposp, offs, left) 94338420Smckusick struct mbuf **mdp; 94438420Smckusick caddr_t *dposp; 94538420Smckusick int offs; 94638420Smckusick int left; 94738420Smckusick { 94838420Smckusick register struct mbuf *m; 94938420Smckusick register int s; 95038420Smckusick 95138420Smckusick m = *mdp; 95238420Smckusick s = left; 95338420Smckusick while (s < offs) { 95438420Smckusick offs -= s; 95538420Smckusick m = m->m_next; 95638420Smckusick if (m == NULL) 95741902Smckusick return (EBADRPC); 95838420Smckusick s = m->m_len; 95938420Smckusick } 96038420Smckusick *mdp = m; 96138420Smckusick *dposp = mtod(m, caddr_t)+offs; 96241902Smckusick return (0); 96338420Smckusick } 96438420Smckusick 96538420Smckusick /* 96638420Smckusick * Copy a string into mbufs for the hard cases... 96738420Smckusick */ 968*68653Smckusick int 96938420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 97038420Smckusick struct mbuf **mb; 97138420Smckusick char **bpos; 97238420Smckusick char *cp; 97338420Smckusick long siz; 97438420Smckusick { 975*68653Smckusick register struct mbuf *m1 = 0, *m2; 97638420Smckusick long left, xfer, len, tlen; 97748049Smckusick u_long *tl; 97838420Smckusick int putsize; 97938420Smckusick 98038420Smckusick putsize = 1; 98138420Smckusick m2 = *mb; 98252196Smckusick left = M_TRAILINGSPACE(m2); 98338420Smckusick if (left > 0) { 98448049Smckusick tl = ((u_long *)(*bpos)); 98548049Smckusick *tl++ = txdr_unsigned(siz); 98638420Smckusick putsize = 0; 98738420Smckusick left -= NFSX_UNSIGNED; 98838420Smckusick m2->m_len += NFSX_UNSIGNED; 98938420Smckusick if (left > 0) { 99048049Smckusick bcopy(cp, (caddr_t) tl, left); 99138420Smckusick siz -= left; 99238420Smckusick cp += left; 99338420Smckusick m2->m_len += left; 99438420Smckusick left = 0; 99538420Smckusick } 99638420Smckusick } 99752196Smckusick /* Loop around adding mbufs */ 99838420Smckusick while (siz > 0) { 99938420Smckusick MGET(m1, M_WAIT, MT_DATA); 100038420Smckusick if (siz > MLEN) 100141902Smckusick MCLGET(m1, M_WAIT); 100238420Smckusick m1->m_len = NFSMSIZ(m1); 100338420Smckusick m2->m_next = m1; 100438420Smckusick m2 = m1; 100548049Smckusick tl = mtod(m1, u_long *); 100638420Smckusick tlen = 0; 100738420Smckusick if (putsize) { 100848049Smckusick *tl++ = txdr_unsigned(siz); 100938420Smckusick m1->m_len -= NFSX_UNSIGNED; 101038420Smckusick tlen = NFSX_UNSIGNED; 101138420Smckusick putsize = 0; 101238420Smckusick } 101338420Smckusick if (siz < m1->m_len) { 101438420Smckusick len = nfsm_rndup(siz); 101538420Smckusick xfer = siz; 101638420Smckusick if (xfer < len) 101748049Smckusick *(tl+(xfer>>2)) = 0; 101838420Smckusick } else { 101938420Smckusick xfer = len = m1->m_len; 102038420Smckusick } 102148049Smckusick bcopy(cp, (caddr_t) tl, xfer); 102238420Smckusick m1->m_len = len+tlen; 102338420Smckusick siz -= xfer; 102438420Smckusick cp += xfer; 102538420Smckusick } 102638420Smckusick *mb = m1; 102738420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 102841902Smckusick return (0); 102938420Smckusick } 103038420Smckusick 103138420Smckusick /* 103238420Smckusick * Called once to initialize data structures... 103338420Smckusick */ 1034*68653Smckusick int 1035*68653Smckusick nfs_init(vfsp) 1036*68653Smckusick struct vfsconf *vfsp; 103738420Smckusick { 103838420Smckusick register int i; 103938420Smckusick 1040*68653Smckusick /* 1041*68653Smckusick * Check to see if major data structures haven't bloated. 1042*68653Smckusick */ 1043*68653Smckusick if (sizeof (struct nfsnode) > NFS_NODEALLOC) { 1044*68653Smckusick printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); 1045*68653Smckusick printf("Try reducing NFS_SMALLFH\n"); 1046*68653Smckusick } 1047*68653Smckusick if (sizeof (struct nfsmount) > NFS_MNTALLOC) { 1048*68653Smckusick printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); 1049*68653Smckusick printf("Try reducing NFS_MUIDHASHSIZ\n"); 1050*68653Smckusick } 1051*68653Smckusick if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 1052*68653Smckusick printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 1053*68653Smckusick printf("Try reducing NFS_UIDHASHSIZ\n"); 1054*68653Smckusick } 1055*68653Smckusick if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 1056*68653Smckusick printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 1057*68653Smckusick printf("Try unionizing the nu_nickname and nu_flag fields\n"); 1058*68653Smckusick } 1059*68653Smckusick nfs_mount_type = vfsp->vfc_typenum; 106052196Smckusick nfsrtt.pos = 0; 106138420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 106238420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 106338420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 106438420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 106538420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 106638420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 106752196Smckusick rpc_autherr = txdr_unsigned(RPC_AUTHERR); 106838420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1069*68653Smckusick rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 107038420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 1071*68653Smckusick nqnfs_prog = txdr_unsigned(NQNFS_PROG); 107238420Smckusick nfs_true = txdr_unsigned(TRUE); 107338420Smckusick nfs_false = txdr_unsigned(FALSE); 1074*68653Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 1075*68653Smckusick nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1076*68653Smckusick if (nfs_ticks < 1) 1077*68653Smckusick nfs_ticks = 1; 107839345Smckusick /* Ensure async daemons disabled */ 107941902Smckusick for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 108039345Smckusick nfs_iodwant[i] = (struct proc *)0; 108165248Smckusick TAILQ_INIT(&nfs_bufq); 108238420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 108352979Smckusick nfsrv_init(0); /* Init server data structures */ 108439755Smckusick nfsrv_initcache(); /* Init the server request cache */ 108541902Smckusick 108641902Smckusick /* 108752196Smckusick * Initialize the nqnfs server stuff. 108852196Smckusick */ 108952196Smckusick if (nqnfsstarttime == 0) { 109052196Smckusick nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 109152196Smckusick + nqsrv_clockskew + nqsrv_writeslack; 109252196Smckusick NQLOADNOVRAM(nqnfsstarttime); 109367708Smckusick CIRCLEQ_INIT(&nqtimerhead); 109467708Smckusick nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 109552196Smckusick } 109652196Smckusick 109752196Smckusick /* 109841902Smckusick * Initialize reply list and start timer 109941902Smckusick */ 110067708Smckusick TAILQ_INIT(&nfs_reqq); 1101*68653Smckusick nfs_timer(0); 1102*68653Smckusick return (0); 110338420Smckusick } 110438420Smckusick 110538420Smckusick /* 110638420Smckusick * Attribute cache routines. 110738420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 110838420Smckusick * that are on the mbuf list 110938420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 111038420Smckusick * error otherwise 111138420Smckusick */ 111238420Smckusick 111338420Smckusick /* 111439444Smckusick * Load the attribute cache (that lives in the nfsnode entry) with 111538420Smckusick * the values on the mbuf list and 111638420Smckusick * Iff vap not NULL 111738420Smckusick * copy the attributes to *vaper 111838420Smckusick */ 1119*68653Smckusick int 112039457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper) 112139457Smckusick struct vnode **vpp; 112238420Smckusick struct mbuf **mdp; 112338420Smckusick caddr_t *dposp; 112438420Smckusick struct vattr *vaper; 112538420Smckusick { 112639457Smckusick register struct vnode *vp = *vpp; 112738420Smckusick register struct vattr *vap; 1128*68653Smckusick register struct nfs_fattr *fp; 112953553Sheideman extern int (**spec_nfsv2nodeop_p)(); 113067708Smckusick register struct nfsnode *np; 113167708Smckusick register struct nfsnodehashhead *nhpp; 113239494Smckusick register long t1; 1133*68653Smckusick caddr_t cp2; 1134*68653Smckusick int error = 0, rdev; 113539494Smckusick struct mbuf *md; 113652196Smckusick enum vtype vtyp; 113752196Smckusick u_short vmode; 113856287Smckusick struct timespec mtime; 113939444Smckusick struct vnode *nvp; 1140*68653Smckusick quad_t tval; 1141*68653Smckusick int v3 = NFS_ISV3(vp); 114238420Smckusick 114338420Smckusick md = *mdp; 1144*68653Smckusick t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1145*68653Smckusick if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) 114638420Smckusick return (error); 1147*68653Smckusick fp = (struct nfs_fattr *)cp2; 1148*68653Smckusick if (v3) { 1149*68653Smckusick vtyp = nfsv3tov_type(fp->fa_type); 1150*68653Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode); 1151*68653Smckusick rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 1152*68653Smckusick fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 1153*68653Smckusick fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 115456287Smckusick } else { 1155*68653Smckusick vtyp = nfsv2tov_type(fp->fa_type); 1156*68653Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode); 1157*68653Smckusick if (vtyp == VNON || vtyp == VREG) 1158*68653Smckusick vtyp = IFTOVT(vmode); 1159*68653Smckusick rdev = fxdr_unsigned(long, fp->fa2_rdev); 1160*68653Smckusick fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1161*68653Smckusick 1162*68653Smckusick /* 1163*68653Smckusick * Really ugly NFSv2 kludge. 1164*68653Smckusick */ 1165*68653Smckusick if (vtyp == VCHR && rdev == 0xffffffff) 1166*68653Smckusick vtyp = VFIFO; 116756287Smckusick } 1168*68653Smckusick 116939444Smckusick /* 117039444Smckusick * If v_type == VNON it is a new node, so fill in the v_type, 117139444Smckusick * n_mtime fields. Check to see if it represents a special 117239444Smckusick * device, and if so, check for a possible alias. Once the 117339444Smckusick * correct vnode has been obtained, fill in the rest of the 117439444Smckusick * information. 117539444Smckusick */ 117638420Smckusick np = VTONFS(vp); 117739444Smckusick if (vp->v_type == VNON) { 1178*68653Smckusick vp->v_type = vtyp; 117940295Smckusick if (vp->v_type == VFIFO) { 118053553Sheideman extern int (**fifo_nfsv2nodeop_p)(); 118153553Sheideman vp->v_op = fifo_nfsv2nodeop_p; 118240295Smckusick } 118339444Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 118453553Sheideman vp->v_op = spec_nfsv2nodeop_p; 1185*68653Smckusick nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 1186*68653Smckusick if (nvp) { 118739444Smckusick /* 118851984Smckusick * Discard unneeded vnode, but save its nfsnode. 118951984Smckusick */ 119067708Smckusick LIST_REMOVE(np, n_hash); 119151984Smckusick nvp->v_data = vp->v_data; 119251984Smckusick vp->v_data = NULL; 119353553Sheideman vp->v_op = spec_vnodeop_p; 119451984Smckusick vrele(vp); 119551984Smckusick vgone(vp); 119651984Smckusick /* 119739444Smckusick * Reinitialize aliased node. 119839444Smckusick */ 119939444Smckusick np->n_vnode = nvp; 1200*68653Smckusick nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize)); 120167708Smckusick LIST_INSERT_HEAD(nhpp, np, n_hash); 120251984Smckusick *vpp = vp = nvp; 120339444Smckusick } 120439444Smckusick } 120556287Smckusick np->n_mtime = mtime.ts_sec; 120639444Smckusick } 120738420Smckusick vap = &np->n_vattr; 120852196Smckusick vap->va_type = vtyp; 120952196Smckusick vap->va_mode = (vmode & 07777); 121056287Smckusick vap->va_rdev = (dev_t)rdev; 121156287Smckusick vap->va_mtime = mtime; 121256287Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1213*68653Smckusick if (v3) { 1214*68653Smckusick vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1215*68653Smckusick vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1216*68653Smckusick vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1217*68653Smckusick fxdr_hyper(&fp->fa3_size, &vap->va_size); 1218*68653Smckusick vap->va_blocksize = NFS_FABLKSIZE; 1219*68653Smckusick fxdr_hyper(&fp->fa3_used, &vap->va_bytes); 1220*68653Smckusick vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]); 1221*68653Smckusick fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1222*68653Smckusick fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1223*68653Smckusick vap->va_flags = 0; 1224*68653Smckusick vap->va_filerev = 0; 122556287Smckusick } else { 1226*68653Smckusick vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1227*68653Smckusick vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1228*68653Smckusick vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1229*68653Smckusick vap->va_size = fxdr_unsigned(u_long, fp->fa2_size); 1230*68653Smckusick vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize); 1231*68653Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE; 1232*68653Smckusick vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid); 1233*68653Smckusick fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 123458881Smckusick vap->va_flags = 0; 1235*68653Smckusick vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec); 123656287Smckusick vap->va_ctime.ts_nsec = 0; 1237*68653Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec); 123856287Smckusick vap->va_filerev = 0; 123956287Smckusick } 124057787Smckusick if (vap->va_size != np->n_size) { 124157787Smckusick if (vap->va_type == VREG) { 124257787Smckusick if (np->n_flag & NMODIFIED) { 124357787Smckusick if (vap->va_size < np->n_size) 124457787Smckusick vap->va_size = np->n_size; 124557787Smckusick else 124657787Smckusick np->n_size = vap->va_size; 124757787Smckusick } else 124857787Smckusick np->n_size = vap->va_size; 124957787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 125057787Smckusick } else 125157787Smckusick np->n_size = vap->va_size; 125245716Smckusick } 125338420Smckusick np->n_attrstamp = time.tv_sec; 125438884Smacklem if (vaper != NULL) { 125538420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 125653628Smckusick if (np->n_flag & NCHG) { 1257*68653Smckusick if (np->n_flag & NACC) 1258*68653Smckusick vaper->va_atime = np->n_atim; 1259*68653Smckusick if (np->n_flag & NUPD) 1260*68653Smckusick vaper->va_mtime = np->n_mtim; 126153628Smckusick } 126238884Smacklem } 126338420Smckusick return (0); 126438420Smckusick } 126538420Smckusick 126638420Smckusick /* 126738420Smckusick * Check the time stamp 126838420Smckusick * If the cache is valid, copy contents to *vap and return 0 126938420Smckusick * otherwise return an error 127038420Smckusick */ 1271*68653Smckusick int 127257787Smckusick nfs_getattrcache(vp, vaper) 127338420Smckusick register struct vnode *vp; 127457787Smckusick struct vattr *vaper; 127538420Smckusick { 127657787Smckusick register struct nfsnode *np = VTONFS(vp); 127757787Smckusick register struct vattr *vap; 127838420Smckusick 1279*68653Smckusick if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 128038420Smckusick nfsstats.attrcache_misses++; 128138420Smckusick return (ENOENT); 128238420Smckusick } 128352196Smckusick nfsstats.attrcache_hits++; 128457787Smckusick vap = &np->n_vattr; 128557787Smckusick if (vap->va_size != np->n_size) { 128657787Smckusick if (vap->va_type == VREG) { 128757787Smckusick if (np->n_flag & NMODIFIED) { 128857787Smckusick if (vap->va_size < np->n_size) 128957787Smckusick vap->va_size = np->n_size; 129057787Smckusick else 129157787Smckusick np->n_size = vap->va_size; 129257787Smckusick } else 129357787Smckusick np->n_size = vap->va_size; 129457787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size); 129557787Smckusick } else 129657787Smckusick np->n_size = vap->va_size; 129757787Smckusick } 129857787Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 129953628Smckusick if (np->n_flag & NCHG) { 1300*68653Smckusick if (np->n_flag & NACC) 1301*68653Smckusick vaper->va_atime = np->n_atim; 1302*68653Smckusick if (np->n_flag & NUPD) 1303*68653Smckusick vaper->va_mtime = np->n_mtim; 130453628Smckusick } 130552196Smckusick return (0); 130638420Smckusick } 130738420Smckusick 130838420Smckusick /* 130952196Smckusick * Set up nameidata for a lookup() call and do it 131038420Smckusick */ 1311*68653Smckusick int 1312*68653Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) 131338420Smckusick register struct nameidata *ndp; 131438420Smckusick fhandle_t *fhp; 131538420Smckusick int len; 131652196Smckusick struct nfssvc_sock *slp; 131752196Smckusick struct mbuf *nam; 131838420Smckusick struct mbuf **mdp; 131938420Smckusick caddr_t *dposp; 1320*68653Smckusick struct vnode **retdirp; 132149739Smckusick struct proc *p; 1322*68653Smckusick int kerbflag; 132338420Smckusick { 132438420Smckusick register int i, rem; 132538420Smckusick register struct mbuf *md; 132649739Smckusick register char *fromcp, *tocp; 132746514Smckusick struct vnode *dp; 132852315Sheideman int error, rdonly; 132952315Sheideman struct componentname *cnp = &ndp->ni_cnd; 133038420Smckusick 1331*68653Smckusick *retdirp = (struct vnode *)0; 133252315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 133349739Smckusick /* 133449739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf 133549739Smckusick * and set the various ndp fields appropriately. 133649739Smckusick */ 133749739Smckusick fromcp = *dposp; 133852315Sheideman tocp = cnp->cn_pnbuf; 133949739Smckusick md = *mdp; 134049739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp; 134152315Sheideman cnp->cn_hash = 0; 134249739Smckusick for (i = 0; i < len; i++) { 134349739Smckusick while (rem == 0) { 134449739Smckusick md = md->m_next; 134549739Smckusick if (md == NULL) { 134649739Smckusick error = EBADRPC; 134749739Smckusick goto out; 134842244Smckusick } 134949739Smckusick fromcp = mtod(md, caddr_t); 135049739Smckusick rem = md->m_len; 135138420Smckusick } 135249739Smckusick if (*fromcp == '\0' || *fromcp == '/') { 1353*68653Smckusick error = EACCES; 135449739Smckusick goto out; 135542244Smckusick } 135652315Sheideman cnp->cn_hash += (unsigned char)*fromcp; 135749739Smckusick *tocp++ = *fromcp++; 135849739Smckusick rem--; 135949739Smckusick } 136049739Smckusick *tocp = '\0'; 136149739Smckusick *mdp = md; 136249739Smckusick *dposp = fromcp; 136349739Smckusick len = nfsm_rndup(len)-len; 136449739Smckusick if (len > 0) { 136549739Smckusick if (rem >= len) 136649739Smckusick *dposp += len; 136749739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem)) 136849739Smckusick goto out; 136949739Smckusick } 137052315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 137152315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf; 137246514Smckusick /* 137346514Smckusick * Extract and set starting directory. 137446514Smckusick */ 137552315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 1376*68653Smckusick nam, &rdonly, kerbflag)) 137749739Smckusick goto out; 137838425Smckusick if (dp->v_type != VDIR) { 137941902Smckusick vrele(dp); 138049739Smckusick error = ENOTDIR; 138149739Smckusick goto out; 138238425Smckusick } 1383*68653Smckusick VREF(dp); 1384*68653Smckusick *retdirp = dp; 138546514Smckusick ndp->ni_startdir = dp; 138652196Smckusick if (rdonly) 138752315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 138852196Smckusick else 138952315Sheideman cnp->cn_flags |= NOCROSSMOUNT; 139039345Smckusick /* 139149739Smckusick * And call lookup() to do the real work 139238420Smckusick */ 139352315Sheideman cnp->cn_proc = p; 139452315Sheideman if (error = lookup(ndp)) 139549739Smckusick goto out; 139649739Smckusick /* 139749739Smckusick * Check for encountering a symbolic link 139849739Smckusick */ 139952315Sheideman if (cnp->cn_flags & ISSYMLINK) { 140052315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 140149739Smckusick vput(ndp->ni_dvp); 140249739Smckusick else 140349739Smckusick vrele(ndp->ni_dvp); 140449739Smckusick vput(ndp->ni_vp); 140549739Smckusick ndp->ni_vp = NULL; 140649739Smckusick error = EINVAL; 140749739Smckusick goto out; 140849739Smckusick } 140949739Smckusick /* 141049739Smckusick * Check for saved name request 141149739Smckusick */ 141252315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 141352315Sheideman cnp->cn_flags |= HASBUF; 141449739Smckusick return (0); 141549739Smckusick } 141649739Smckusick out: 141752315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI); 141838420Smckusick return (error); 141938420Smckusick } 142038420Smckusick 142138420Smckusick /* 142238420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 142338420Smckusick * boundary and only trims off the back end 142438420Smckusick */ 142552196Smckusick void 142638420Smckusick nfsm_adj(mp, len, nul) 142738420Smckusick struct mbuf *mp; 142838420Smckusick register int len; 142938420Smckusick int nul; 143038420Smckusick { 143138420Smckusick register struct mbuf *m; 143238420Smckusick register int count, i; 143338420Smckusick register char *cp; 143438420Smckusick 143538420Smckusick /* 143638420Smckusick * Trim from tail. Scan the mbuf chain, 143738420Smckusick * calculating its length and finding the last mbuf. 143838420Smckusick * If the adjustment only affects this mbuf, then just 143938420Smckusick * adjust and return. Otherwise, rescan and truncate 144038420Smckusick * after the remaining size. 144138420Smckusick */ 144238420Smckusick count = 0; 144338420Smckusick m = mp; 144438420Smckusick for (;;) { 144538420Smckusick count += m->m_len; 144638420Smckusick if (m->m_next == (struct mbuf *)0) 144738420Smckusick break; 144838420Smckusick m = m->m_next; 144938420Smckusick } 145038579Smckusick if (m->m_len > len) { 145138420Smckusick m->m_len -= len; 145238420Smckusick if (nul > 0) { 145338420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 145438420Smckusick for (i = 0; i < nul; i++) 145538420Smckusick *cp++ = '\0'; 145638420Smckusick } 145738420Smckusick return; 145838420Smckusick } 145938420Smckusick count -= len; 146038420Smckusick if (count < 0) 146138420Smckusick count = 0; 146238420Smckusick /* 146338420Smckusick * Correct length for chain is "count". 146438420Smckusick * Find the mbuf with last data, adjust its length, 146538420Smckusick * and toss data from remaining mbufs on chain. 146638420Smckusick */ 146738420Smckusick for (m = mp; m; m = m->m_next) { 146838420Smckusick if (m->m_len >= count) { 146938420Smckusick m->m_len = count; 147038420Smckusick if (nul > 0) { 147138420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 147238420Smckusick for (i = 0; i < nul; i++) 147338420Smckusick *cp++ = '\0'; 147438420Smckusick } 147538420Smckusick break; 147638420Smckusick } 147738420Smckusick count -= m->m_len; 147838420Smckusick } 1479*68653Smckusick for (m = m->m_next;m;m = m->m_next) 148038420Smckusick m->m_len = 0; 148138420Smckusick } 148238420Smckusick 148338420Smckusick /* 1484*68653Smckusick * Make these functions instead of macros, so that the kernel text size 1485*68653Smckusick * doesn't get too big... 1486*68653Smckusick */ 1487*68653Smckusick void 1488*68653Smckusick nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 1489*68653Smckusick struct nfsrv_descript *nfsd; 1490*68653Smckusick int before_ret; 1491*68653Smckusick register struct vattr *before_vap; 1492*68653Smckusick int after_ret; 1493*68653Smckusick struct vattr *after_vap; 1494*68653Smckusick struct mbuf **mbp; 1495*68653Smckusick char **bposp; 1496*68653Smckusick { 1497*68653Smckusick register struct mbuf *mb = *mbp, *mb2; 1498*68653Smckusick register char *bpos = *bposp; 1499*68653Smckusick register u_long *tl; 1500*68653Smckusick 1501*68653Smckusick if (before_ret) { 1502*68653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 1503*68653Smckusick *tl = nfs_false; 1504*68653Smckusick } else { 1505*68653Smckusick nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED); 1506*68653Smckusick *tl++ = nfs_true; 1507*68653Smckusick txdr_hyper(&(before_vap->va_size), tl); 1508*68653Smckusick tl += 2; 1509*68653Smckusick txdr_nfsv3time(&(before_vap->va_mtime), tl); 1510*68653Smckusick tl += 2; 1511*68653Smckusick txdr_nfsv3time(&(before_vap->va_ctime), tl); 1512*68653Smckusick } 1513*68653Smckusick *bposp = bpos; 1514*68653Smckusick *mbp = mb; 1515*68653Smckusick nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1516*68653Smckusick } 1517*68653Smckusick 1518*68653Smckusick void 1519*68653Smckusick nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 1520*68653Smckusick struct nfsrv_descript *nfsd; 1521*68653Smckusick int after_ret; 1522*68653Smckusick struct vattr *after_vap; 1523*68653Smckusick struct mbuf **mbp; 1524*68653Smckusick char **bposp; 1525*68653Smckusick { 1526*68653Smckusick register struct mbuf *mb = *mbp, *mb2; 1527*68653Smckusick register char *bpos = *bposp; 1528*68653Smckusick register u_long *tl; 1529*68653Smckusick register struct nfs_fattr *fp; 1530*68653Smckusick 1531*68653Smckusick if (after_ret) { 1532*68653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED); 1533*68653Smckusick *tl = nfs_false; 1534*68653Smckusick } else { 1535*68653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR); 1536*68653Smckusick *tl++ = nfs_true; 1537*68653Smckusick fp = (struct nfs_fattr *)tl; 1538*68653Smckusick nfsm_srvfattr(nfsd, after_vap, fp); 1539*68653Smckusick } 1540*68653Smckusick *mbp = mb; 1541*68653Smckusick *bposp = bpos; 1542*68653Smckusick } 1543*68653Smckusick 1544*68653Smckusick void 1545*68653Smckusick nfsm_srvfattr(nfsd, vap, fp) 1546*68653Smckusick register struct nfsrv_descript *nfsd; 1547*68653Smckusick register struct vattr *vap; 1548*68653Smckusick register struct nfs_fattr *fp; 1549*68653Smckusick { 1550*68653Smckusick 1551*68653Smckusick fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1552*68653Smckusick fp->fa_uid = txdr_unsigned(vap->va_uid); 1553*68653Smckusick fp->fa_gid = txdr_unsigned(vap->va_gid); 1554*68653Smckusick if (nfsd->nd_flag & ND_NFSV3) { 1555*68653Smckusick fp->fa_type = vtonfsv3_type(vap->va_type); 1556*68653Smckusick fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1557*68653Smckusick txdr_hyper(&vap->va_size, &fp->fa3_size); 1558*68653Smckusick txdr_hyper(&vap->va_bytes, &fp->fa3_used); 1559*68653Smckusick fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 1560*68653Smckusick fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 1561*68653Smckusick fp->fa3_fsid.nfsuquad[0] = 0; 1562*68653Smckusick fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1563*68653Smckusick fp->fa3_fileid.nfsuquad[0] = 0; 1564*68653Smckusick fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1565*68653Smckusick txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1566*68653Smckusick txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1567*68653Smckusick txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1568*68653Smckusick } else { 1569*68653Smckusick fp->fa_type = vtonfsv2_type(vap->va_type); 1570*68653Smckusick fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1571*68653Smckusick fp->fa2_size = txdr_unsigned(vap->va_size); 1572*68653Smckusick fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1573*68653Smckusick if (vap->va_type == VFIFO) 1574*68653Smckusick fp->fa2_rdev = 0xffffffff; 1575*68653Smckusick else 1576*68653Smckusick fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1577*68653Smckusick fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1578*68653Smckusick fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1579*68653Smckusick fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1580*68653Smckusick txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1581*68653Smckusick txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1582*68653Smckusick txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1583*68653Smckusick } 1584*68653Smckusick } 1585*68653Smckusick 1586*68653Smckusick /* 158738420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 158838420Smckusick * - look up fsid in mount list (if not found ret error) 158954739Smckusick * - get vp and export rights by calling VFS_FHTOVP() 159054739Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 159138420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 159238420Smckusick */ 1593*68653Smckusick int 1594*68653Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) 159538420Smckusick fhandle_t *fhp; 159638420Smckusick int lockflag; 159738420Smckusick struct vnode **vpp; 159838420Smckusick struct ucred *cred; 159952196Smckusick struct nfssvc_sock *slp; 160052196Smckusick struct mbuf *nam; 160152196Smckusick int *rdonlyp; 1602*68653Smckusick int kerbflag; 160338420Smckusick { 160438420Smckusick register struct mount *mp; 160552196Smckusick register struct nfsuid *uidp; 160657787Smckusick register int i; 160754739Smckusick struct ucred *credanon; 160854739Smckusick int error, exflags; 160938420Smckusick 161052196Smckusick *vpp = (struct vnode *)0; 1611*68653Smckusick mp = vfs_getvfs(&fhp->fh_fsid); 1612*68653Smckusick if (!mp) 161338420Smckusick return (ESTALE); 1614*68653Smckusick error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 1615*68653Smckusick if (error) 161654739Smckusick return (error); 161752196Smckusick /* 161852196Smckusick * Check/setup credentials. 161952196Smckusick */ 162054739Smckusick if (exflags & MNT_EXKERB) { 1621*68653Smckusick if (!kerbflag) { 162257787Smckusick vput(*vpp); 1623*68653Smckusick return (NFSERR_AUTHERR | AUTH_TOOWEAK); 162457787Smckusick } 1625*68653Smckusick } else if (kerbflag) { 1626*68653Smckusick vput(*vpp); 1627*68653Smckusick return (NFSERR_AUTHERR | AUTH_TOOWEAK); 162857787Smckusick } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 162957787Smckusick cred->cr_uid = credanon->cr_uid; 163057787Smckusick for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 163157787Smckusick cred->cr_groups[i] = credanon->cr_groups[i]; 163267567Smckusick cred->cr_ngroups = i; 163357787Smckusick } 163454739Smckusick if (exflags & MNT_EXRDONLY) 163552196Smckusick *rdonlyp = 1; 163645282Smckusick else 163752196Smckusick *rdonlyp = 0; 163852196Smckusick if (!lockflag) 163952196Smckusick VOP_UNLOCK(*vpp); 164052196Smckusick return (0); 164145282Smckusick } 164254988Smckusick 164354988Smckusick /* 164454988Smckusick * This function compares two net addresses by family and returns TRUE 164554988Smckusick * if they are the same host. 164654988Smckusick * If there is any doubt, return FALSE. 164754988Smckusick * The AF_INET family is handled as a special case so that address mbufs 164854988Smckusick * don't need to be saved to store "struct in_addr", which is only 4 bytes. 164954988Smckusick */ 1650*68653Smckusick int 165156363Smckusick netaddr_match(family, haddr, nam) 165254988Smckusick int family; 165354988Smckusick union nethostaddr *haddr; 165454988Smckusick struct mbuf *nam; 165554988Smckusick { 165654988Smckusick register struct sockaddr_in *inetaddr; 165754988Smckusick 165854988Smckusick switch (family) { 165954988Smckusick case AF_INET: 166054988Smckusick inetaddr = mtod(nam, struct sockaddr_in *); 166156363Smckusick if (inetaddr->sin_family == AF_INET && 166256363Smckusick inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 166354988Smckusick return (1); 166454988Smckusick break; 166554988Smckusick #ifdef ISO 166654988Smckusick case AF_ISO: 166756363Smckusick { 166856363Smckusick register struct sockaddr_iso *isoaddr1, *isoaddr2; 166956363Smckusick 167054988Smckusick isoaddr1 = mtod(nam, struct sockaddr_iso *); 167154988Smckusick isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 167256363Smckusick if (isoaddr1->siso_family == AF_ISO && 167356363Smckusick isoaddr1->siso_nlen > 0 && 167454988Smckusick isoaddr1->siso_nlen == isoaddr2->siso_nlen && 167554988Smckusick SAME_ISOADDR(isoaddr1, isoaddr2)) 167654988Smckusick return (1); 167754988Smckusick break; 167856363Smckusick } 167954988Smckusick #endif /* ISO */ 168054988Smckusick default: 168154988Smckusick break; 168254988Smckusick }; 168354988Smckusick return (0); 168454988Smckusick } 1685*68653Smckusick 1686*68653Smckusick static nfsuint64 nfs_nullcookie = { 0, 0 }; 1687*68653Smckusick /* 1688*68653Smckusick * This function finds the directory cookie that corresponds to the 1689*68653Smckusick * logical byte offset given. 1690*68653Smckusick */ 1691*68653Smckusick nfsuint64 * 1692*68653Smckusick nfs_getcookie(np, off, add) 1693*68653Smckusick register struct nfsnode *np; 1694*68653Smckusick off_t off; 1695*68653Smckusick int add; 1696*68653Smckusick { 1697*68653Smckusick register struct nfsdmap *dp, *dp2; 1698*68653Smckusick register int pos; 1699*68653Smckusick 1700*68653Smckusick pos = off / NFS_DIRBLKSIZ; 1701*68653Smckusick if (pos == 0) { 1702*68653Smckusick #ifdef DIAGNOSTIC 1703*68653Smckusick if (add) 1704*68653Smckusick panic("nfs getcookie add at 0"); 1705*68653Smckusick #endif 1706*68653Smckusick return (&nfs_nullcookie); 1707*68653Smckusick } 1708*68653Smckusick pos--; 1709*68653Smckusick dp = np->n_cookies.lh_first; 1710*68653Smckusick if (!dp) { 1711*68653Smckusick if (add) { 1712*68653Smckusick MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 1713*68653Smckusick M_NFSDIROFF, M_WAITOK); 1714*68653Smckusick dp->ndm_eocookie = 0; 1715*68653Smckusick LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 1716*68653Smckusick } else 1717*68653Smckusick return ((nfsuint64 *)0); 1718*68653Smckusick } 1719*68653Smckusick while (pos >= NFSNUMCOOKIES) { 1720*68653Smckusick pos -= NFSNUMCOOKIES; 1721*68653Smckusick if (dp->ndm_list.le_next) { 1722*68653Smckusick if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 1723*68653Smckusick pos >= dp->ndm_eocookie) 1724*68653Smckusick return ((nfsuint64 *)0); 1725*68653Smckusick dp = dp->ndm_list.le_next; 1726*68653Smckusick } else if (add) { 1727*68653Smckusick MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 1728*68653Smckusick M_NFSDIROFF, M_WAITOK); 1729*68653Smckusick dp2->ndm_eocookie = 0; 1730*68653Smckusick LIST_INSERT_AFTER(dp, dp2, ndm_list); 1731*68653Smckusick dp = dp2; 1732*68653Smckusick } else 1733*68653Smckusick return ((nfsuint64 *)0); 1734*68653Smckusick } 1735*68653Smckusick if (pos >= dp->ndm_eocookie) { 1736*68653Smckusick if (add) 1737*68653Smckusick dp->ndm_eocookie = pos + 1; 1738*68653Smckusick else 1739*68653Smckusick return ((nfsuint64 *)0); 1740*68653Smckusick } 1741*68653Smckusick return (&dp->ndm_cookies[pos]); 1742*68653Smckusick } 1743*68653Smckusick 1744*68653Smckusick /* 1745*68653Smckusick * Invalidate cached directory information, except for the actual directory 1746*68653Smckusick * blocks (which are invalidated separately). 1747*68653Smckusick * Done mainly to avoid the use of stale offset cookies. 1748*68653Smckusick */ 1749*68653Smckusick void 1750*68653Smckusick nfs_invaldir(vp) 1751*68653Smckusick register struct vnode *vp; 1752*68653Smckusick { 1753*68653Smckusick register struct nfsnode *np = VTONFS(vp); 1754*68653Smckusick 1755*68653Smckusick #ifdef DIAGNOSTIC 1756*68653Smckusick if (vp->v_type != VDIR) 1757*68653Smckusick panic("nfs: invaldir not dir"); 1758*68653Smckusick #endif 1759*68653Smckusick np->n_direofoffset = 0; 1760*68653Smckusick np->n_cookieverf.nfsuquad[0] = 0; 1761*68653Smckusick np->n_cookieverf.nfsuquad[1] = 0; 1762*68653Smckusick if (np->n_cookies.lh_first) 1763*68653Smckusick np->n_cookies.lh_first->ndm_eocookie = 0; 1764*68653Smckusick } 1765*68653Smckusick 1766*68653Smckusick /* 1767*68653Smckusick * The write verifier has changed (probably due to a server reboot), so all 1768*68653Smckusick * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 1769*68653Smckusick * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 1770*68653Smckusick * flag. Once done the new write verifier can be set for the mount point. 1771*68653Smckusick */ 1772*68653Smckusick void 1773*68653Smckusick nfs_clearcommit(mp) 1774*68653Smckusick struct mount *mp; 1775*68653Smckusick { 1776*68653Smckusick register struct vnode *vp, *nvp; 1777*68653Smckusick register struct buf *bp, *nbp; 1778*68653Smckusick int s; 1779*68653Smckusick 1780*68653Smckusick s = splbio(); 1781*68653Smckusick loop: 1782*68653Smckusick for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 1783*68653Smckusick if (vp->v_mount != mp) /* Paranoia */ 1784*68653Smckusick goto loop; 1785*68653Smckusick nvp = vp->v_mntvnodes.le_next; 1786*68653Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 1787*68653Smckusick nbp = bp->b_vnbufs.le_next; 1788*68653Smckusick if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) 1789*68653Smckusick == (B_DELWRI | B_NEEDCOMMIT)) 1790*68653Smckusick bp->b_flags &= ~B_NEEDCOMMIT; 1791*68653Smckusick } 1792*68653Smckusick } 1793*68653Smckusick splx(s); 1794*68653Smckusick } 1795*68653Smckusick 1796*68653Smckusick /* 1797*68653Smckusick * Map errnos to NFS error numbers. For Version 3 also filter out error 1798*68653Smckusick * numbers not specified for the associated procedure. 1799*68653Smckusick */ 1800*68653Smckusick int 1801*68653Smckusick nfsrv_errmap(nd, err) 1802*68653Smckusick struct nfsrv_descript *nd; 1803*68653Smckusick register int err; 1804*68653Smckusick { 1805*68653Smckusick register short *defaulterrp, *errp; 1806*68653Smckusick 1807*68653Smckusick if (nd->nd_flag & ND_NFSV3) { 1808*68653Smckusick if (nd->nd_procnum <= NFSPROC_COMMIT) { 1809*68653Smckusick errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1810*68653Smckusick while (*++errp) { 1811*68653Smckusick if (*errp == err) 1812*68653Smckusick return (err); 1813*68653Smckusick else if (*errp > err) 1814*68653Smckusick break; 1815*68653Smckusick } 1816*68653Smckusick return ((int)*defaulterrp); 1817*68653Smckusick } else 1818*68653Smckusick return (err & 0xffff); 1819*68653Smckusick } 1820*68653Smckusick if (err <= ELAST) 1821*68653Smckusick return ((int)nfsrv_v2errmap[err - 1]); 1822*68653Smckusick return (NFSERR_IO); 1823*68653Smckusick } 1824