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*69606Smckusick * @(#)nfs_subs.c 8.8 (Berkeley) 05/22/95
1138420Smckusick */
1238420Smckusick
1368653Smckusick
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>
2968653Smckusick #include <sys/malloc.h>
3068653Smckusick #ifdef VFS_LKM
3168653Smckusick #include <sys/sysent.h>
3268653Smckusick #include <sys/syscall.h>
3368653Smckusick #endif
3447573Skarels
3568653Smckusick #include <vm/vm.h>
3668653Smckusick
3753322Smckusick #include <nfs/rpcv2.h>
3868653Smckusick #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,
6068653Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
6152196Smckusick rpc_auth_kerb;
6268653Smckusick u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
6352196Smckusick
6438420Smckusick /* And other global data */
6552196Smckusick static u_long nfs_xid = 0;
6668653Smckusick enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
6768653Smckusick enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
6868653Smckusick int nfs_mount_type;
6968653Smckusick int nfs_ticks;
7068653Smckusick
7168653Smckusick /*
7268653Smckusick * Mapping of old NFS Version 2 RPC numbers to generic numbers.
7368653Smckusick */
7468653Smckusick int nfsv3_procid[NFS_NPROCS] = {
7568653Smckusick NFSPROC_NULL,
7668653Smckusick NFSPROC_GETATTR,
7768653Smckusick NFSPROC_SETATTR,
7868653Smckusick NFSPROC_NOOP,
7968653Smckusick NFSPROC_LOOKUP,
8068653Smckusick NFSPROC_READLINK,
8168653Smckusick NFSPROC_READ,
8268653Smckusick NFSPROC_NOOP,
8368653Smckusick NFSPROC_WRITE,
8468653Smckusick NFSPROC_CREATE,
8568653Smckusick NFSPROC_REMOVE,
8668653Smckusick NFSPROC_RENAME,
8768653Smckusick NFSPROC_LINK,
8868653Smckusick NFSPROC_SYMLINK,
8968653Smckusick NFSPROC_MKDIR,
9068653Smckusick NFSPROC_RMDIR,
9168653Smckusick NFSPROC_READDIR,
9268653Smckusick NFSPROC_FSSTAT,
9368653Smckusick NFSPROC_NOOP,
9468653Smckusick NFSPROC_NOOP,
9568653Smckusick NFSPROC_NOOP,
9668653Smckusick NFSPROC_NOOP,
9768653Smckusick NFSPROC_NOOP,
9868653Smckusick NFSPROC_NOOP,
9968653Smckusick NFSPROC_NOOP,
10068653Smckusick NFSPROC_NOOP
10168653Smckusick };
10268653Smckusick
10368653Smckusick /*
10468653Smckusick * and the reverse mapping from generic to Version 2 procedure numbers
10568653Smckusick */
10668653Smckusick int nfsv2_procid[NFS_NPROCS] = {
10768653Smckusick NFSV2PROC_NULL,
10868653Smckusick NFSV2PROC_GETATTR,
10968653Smckusick NFSV2PROC_SETATTR,
11068653Smckusick NFSV2PROC_LOOKUP,
11168653Smckusick NFSV2PROC_NOOP,
11268653Smckusick NFSV2PROC_READLINK,
11368653Smckusick NFSV2PROC_READ,
11468653Smckusick NFSV2PROC_WRITE,
11568653Smckusick NFSV2PROC_CREATE,
11668653Smckusick NFSV2PROC_MKDIR,
11768653Smckusick NFSV2PROC_SYMLINK,
11868653Smckusick NFSV2PROC_CREATE,
11968653Smckusick NFSV2PROC_REMOVE,
12068653Smckusick NFSV2PROC_RMDIR,
12168653Smckusick NFSV2PROC_RENAME,
12268653Smckusick NFSV2PROC_LINK,
12368653Smckusick NFSV2PROC_READDIR,
12468653Smckusick NFSV2PROC_NOOP,
12568653Smckusick NFSV2PROC_STATFS,
12668653Smckusick NFSV2PROC_NOOP,
12768653Smckusick NFSV2PROC_NOOP,
12868653Smckusick NFSV2PROC_NOOP,
12968653Smckusick NFSV2PROC_NOOP,
13068653Smckusick NFSV2PROC_NOOP,
13168653Smckusick NFSV2PROC_NOOP,
13268653Smckusick NFSV2PROC_NOOP,
13368653Smckusick };
13468653Smckusick
13568653Smckusick /*
13668653Smckusick * Maps errno values to nfs error numbers.
13768653Smckusick * Use NFSERR_IO as the catch all for ones not specifically defined in
13868653Smckusick * RFC 1094.
13968653Smckusick */
14068653Smckusick static u_char nfsrv_v2errmap[ELAST] = {
14168653Smckusick NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
14268653Smckusick NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
14368653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
14468653Smckusick NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
14568653Smckusick NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
14668653Smckusick NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
14768653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
14868653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
14968653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
15068653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
15168653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
15268653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
15368653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
15468653Smckusick NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
15568653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
15668653Smckusick NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
15768653Smckusick NFSERR_IO,
15868653Smckusick };
15968653Smckusick
16068653Smckusick /*
16168653Smckusick * Maps errno values to nfs error numbers.
16268653Smckusick * Although it is not obvious whether or not NFS clients really care if
16368653Smckusick * a returned error value is in the specified list for the procedure, the
16468653Smckusick * safest thing to do is filter them appropriately. For Version 2, the
16568653Smckusick * X/Open XNFS document is the only specification that defines error values
16668653Smckusick * for each RPC (The RFC simply lists all possible error values for all RPCs),
16768653Smckusick * so I have decided to not do this for Version 2.
16868653Smckusick * The first entry is the default error return and the rest are the valid
16968653Smckusick * errors for that RPC in increasing numeric order.
17068653Smckusick */
17168653Smckusick static short nfsv3err_null[] = {
17268653Smckusick 0,
17368653Smckusick 0,
17468653Smckusick };
17568653Smckusick
17668653Smckusick static short nfsv3err_getattr[] = {
17768653Smckusick NFSERR_IO,
17868653Smckusick NFSERR_IO,
17968653Smckusick NFSERR_STALE,
18068653Smckusick NFSERR_BADHANDLE,
18168653Smckusick NFSERR_SERVERFAULT,
18268653Smckusick 0,
18368653Smckusick };
18468653Smckusick
18568653Smckusick static short nfsv3err_setattr[] = {
18668653Smckusick NFSERR_IO,
18768653Smckusick NFSERR_PERM,
18868653Smckusick NFSERR_IO,
18968653Smckusick NFSERR_ACCES,
19068653Smckusick NFSERR_INVAL,
19168653Smckusick NFSERR_NOSPC,
19268653Smckusick NFSERR_ROFS,
19368653Smckusick NFSERR_DQUOT,
19468653Smckusick NFSERR_STALE,
19568653Smckusick NFSERR_BADHANDLE,
19668653Smckusick NFSERR_NOT_SYNC,
19768653Smckusick NFSERR_SERVERFAULT,
19868653Smckusick 0,
19968653Smckusick };
20068653Smckusick
20168653Smckusick static short nfsv3err_lookup[] = {
20268653Smckusick NFSERR_IO,
20368653Smckusick NFSERR_NOENT,
20468653Smckusick NFSERR_IO,
20568653Smckusick NFSERR_ACCES,
20668653Smckusick NFSERR_NOTDIR,
20768653Smckusick NFSERR_NAMETOL,
20868653Smckusick NFSERR_STALE,
20968653Smckusick NFSERR_BADHANDLE,
21068653Smckusick NFSERR_SERVERFAULT,
21168653Smckusick 0,
21268653Smckusick };
21368653Smckusick
21468653Smckusick static short nfsv3err_access[] = {
21568653Smckusick NFSERR_IO,
21668653Smckusick NFSERR_IO,
21768653Smckusick NFSERR_STALE,
21868653Smckusick NFSERR_BADHANDLE,
21968653Smckusick NFSERR_SERVERFAULT,
22068653Smckusick 0,
22168653Smckusick };
22268653Smckusick
22368653Smckusick static short nfsv3err_readlink[] = {
22468653Smckusick NFSERR_IO,
22568653Smckusick NFSERR_IO,
22668653Smckusick NFSERR_ACCES,
22768653Smckusick NFSERR_INVAL,
22868653Smckusick NFSERR_STALE,
22968653Smckusick NFSERR_BADHANDLE,
23068653Smckusick NFSERR_NOTSUPP,
23168653Smckusick NFSERR_SERVERFAULT,
23268653Smckusick 0,
23368653Smckusick };
23468653Smckusick
23568653Smckusick static short nfsv3err_read[] = {
23668653Smckusick NFSERR_IO,
23768653Smckusick NFSERR_IO,
23868653Smckusick NFSERR_NXIO,
23968653Smckusick NFSERR_ACCES,
24068653Smckusick NFSERR_INVAL,
24168653Smckusick NFSERR_STALE,
24268653Smckusick NFSERR_BADHANDLE,
24368653Smckusick NFSERR_SERVERFAULT,
24468653Smckusick 0,
24568653Smckusick };
24668653Smckusick
24768653Smckusick static short nfsv3err_write[] = {
24868653Smckusick NFSERR_IO,
24968653Smckusick NFSERR_IO,
25068653Smckusick NFSERR_ACCES,
25168653Smckusick NFSERR_INVAL,
25268653Smckusick NFSERR_FBIG,
25368653Smckusick NFSERR_NOSPC,
25468653Smckusick NFSERR_ROFS,
25568653Smckusick NFSERR_DQUOT,
25668653Smckusick NFSERR_STALE,
25768653Smckusick NFSERR_BADHANDLE,
25868653Smckusick NFSERR_SERVERFAULT,
25968653Smckusick 0,
26068653Smckusick };
26168653Smckusick
26268653Smckusick static short nfsv3err_create[] = {
26368653Smckusick NFSERR_IO,
26468653Smckusick NFSERR_IO,
26568653Smckusick NFSERR_ACCES,
26668653Smckusick NFSERR_EXIST,
26768653Smckusick NFSERR_NOTDIR,
26868653Smckusick NFSERR_NOSPC,
26968653Smckusick NFSERR_ROFS,
27068653Smckusick NFSERR_NAMETOL,
27168653Smckusick NFSERR_DQUOT,
27268653Smckusick NFSERR_STALE,
27368653Smckusick NFSERR_BADHANDLE,
27468653Smckusick NFSERR_NOTSUPP,
27568653Smckusick NFSERR_SERVERFAULT,
27668653Smckusick 0,
27768653Smckusick };
27868653Smckusick
27968653Smckusick static short nfsv3err_mkdir[] = {
28068653Smckusick NFSERR_IO,
28168653Smckusick NFSERR_IO,
28268653Smckusick NFSERR_ACCES,
28368653Smckusick NFSERR_EXIST,
28468653Smckusick NFSERR_NOTDIR,
28568653Smckusick NFSERR_NOSPC,
28668653Smckusick NFSERR_ROFS,
28768653Smckusick NFSERR_NAMETOL,
28868653Smckusick NFSERR_DQUOT,
28968653Smckusick NFSERR_STALE,
29068653Smckusick NFSERR_BADHANDLE,
29168653Smckusick NFSERR_NOTSUPP,
29268653Smckusick NFSERR_SERVERFAULT,
29368653Smckusick 0,
29468653Smckusick };
29568653Smckusick
29668653Smckusick static short nfsv3err_symlink[] = {
29768653Smckusick NFSERR_IO,
29868653Smckusick NFSERR_IO,
29968653Smckusick NFSERR_ACCES,
30068653Smckusick NFSERR_EXIST,
30168653Smckusick NFSERR_NOTDIR,
30268653Smckusick NFSERR_NOSPC,
30368653Smckusick NFSERR_ROFS,
30468653Smckusick NFSERR_NAMETOL,
30568653Smckusick NFSERR_DQUOT,
30668653Smckusick NFSERR_STALE,
30768653Smckusick NFSERR_BADHANDLE,
30868653Smckusick NFSERR_NOTSUPP,
30968653Smckusick NFSERR_SERVERFAULT,
31068653Smckusick 0,
31168653Smckusick };
31268653Smckusick
31368653Smckusick static short nfsv3err_mknod[] = {
31468653Smckusick NFSERR_IO,
31568653Smckusick NFSERR_IO,
31668653Smckusick NFSERR_ACCES,
31768653Smckusick NFSERR_EXIST,
31868653Smckusick NFSERR_NOTDIR,
31968653Smckusick NFSERR_NOSPC,
32068653Smckusick NFSERR_ROFS,
32168653Smckusick NFSERR_NAMETOL,
32268653Smckusick NFSERR_DQUOT,
32368653Smckusick NFSERR_STALE,
32468653Smckusick NFSERR_BADHANDLE,
32568653Smckusick NFSERR_NOTSUPP,
32668653Smckusick NFSERR_SERVERFAULT,
32768653Smckusick NFSERR_BADTYPE,
32868653Smckusick 0,
32968653Smckusick };
33068653Smckusick
33168653Smckusick static short nfsv3err_remove[] = {
33268653Smckusick NFSERR_IO,
33368653Smckusick NFSERR_NOENT,
33468653Smckusick NFSERR_IO,
33568653Smckusick NFSERR_ACCES,
33668653Smckusick NFSERR_NOTDIR,
33768653Smckusick NFSERR_ROFS,
33868653Smckusick NFSERR_NAMETOL,
33968653Smckusick NFSERR_STALE,
34068653Smckusick NFSERR_BADHANDLE,
34168653Smckusick NFSERR_SERVERFAULT,
34268653Smckusick 0,
34368653Smckusick };
34468653Smckusick
34568653Smckusick static short nfsv3err_rmdir[] = {
34668653Smckusick NFSERR_IO,
34768653Smckusick NFSERR_NOENT,
34868653Smckusick NFSERR_IO,
34968653Smckusick NFSERR_ACCES,
35068653Smckusick NFSERR_EXIST,
35168653Smckusick NFSERR_NOTDIR,
35268653Smckusick NFSERR_INVAL,
35368653Smckusick NFSERR_ROFS,
35468653Smckusick NFSERR_NAMETOL,
35568653Smckusick NFSERR_NOTEMPTY,
35668653Smckusick NFSERR_STALE,
35768653Smckusick NFSERR_BADHANDLE,
35868653Smckusick NFSERR_NOTSUPP,
35968653Smckusick NFSERR_SERVERFAULT,
36068653Smckusick 0,
36168653Smckusick };
36268653Smckusick
36368653Smckusick static short nfsv3err_rename[] = {
36468653Smckusick NFSERR_IO,
36568653Smckusick NFSERR_NOENT,
36668653Smckusick NFSERR_IO,
36768653Smckusick NFSERR_ACCES,
36868653Smckusick NFSERR_EXIST,
36968653Smckusick NFSERR_XDEV,
37068653Smckusick NFSERR_NOTDIR,
37168653Smckusick NFSERR_ISDIR,
37268653Smckusick NFSERR_INVAL,
37368653Smckusick NFSERR_NOSPC,
37468653Smckusick NFSERR_ROFS,
37568653Smckusick NFSERR_MLINK,
37668653Smckusick NFSERR_NAMETOL,
37768653Smckusick NFSERR_NOTEMPTY,
37868653Smckusick NFSERR_DQUOT,
37968653Smckusick NFSERR_STALE,
38068653Smckusick NFSERR_BADHANDLE,
38168653Smckusick NFSERR_NOTSUPP,
38268653Smckusick NFSERR_SERVERFAULT,
38368653Smckusick 0,
38468653Smckusick };
38568653Smckusick
38668653Smckusick static short nfsv3err_link[] = {
38768653Smckusick NFSERR_IO,
38868653Smckusick NFSERR_IO,
38968653Smckusick NFSERR_ACCES,
39068653Smckusick NFSERR_EXIST,
39168653Smckusick NFSERR_XDEV,
39268653Smckusick NFSERR_NOTDIR,
39368653Smckusick NFSERR_INVAL,
39468653Smckusick NFSERR_NOSPC,
39568653Smckusick NFSERR_ROFS,
39668653Smckusick NFSERR_MLINK,
39768653Smckusick NFSERR_NAMETOL,
39868653Smckusick NFSERR_DQUOT,
39968653Smckusick NFSERR_STALE,
40068653Smckusick NFSERR_BADHANDLE,
40168653Smckusick NFSERR_NOTSUPP,
40268653Smckusick NFSERR_SERVERFAULT,
40368653Smckusick 0,
40468653Smckusick };
40568653Smckusick
40668653Smckusick static short nfsv3err_readdir[] = {
40768653Smckusick NFSERR_IO,
40868653Smckusick NFSERR_IO,
40968653Smckusick NFSERR_ACCES,
41068653Smckusick NFSERR_NOTDIR,
41168653Smckusick NFSERR_STALE,
41268653Smckusick NFSERR_BADHANDLE,
41368653Smckusick NFSERR_BAD_COOKIE,
41468653Smckusick NFSERR_TOOSMALL,
41568653Smckusick NFSERR_SERVERFAULT,
41668653Smckusick 0,
41768653Smckusick };
41868653Smckusick
41968653Smckusick static short nfsv3err_readdirplus[] = {
42068653Smckusick NFSERR_IO,
42168653Smckusick NFSERR_IO,
42268653Smckusick NFSERR_ACCES,
42368653Smckusick NFSERR_NOTDIR,
42468653Smckusick NFSERR_STALE,
42568653Smckusick NFSERR_BADHANDLE,
42668653Smckusick NFSERR_BAD_COOKIE,
42768653Smckusick NFSERR_NOTSUPP,
42868653Smckusick NFSERR_TOOSMALL,
42968653Smckusick NFSERR_SERVERFAULT,
43068653Smckusick 0,
43168653Smckusick };
43268653Smckusick
43368653Smckusick static short nfsv3err_fsstat[] = {
43468653Smckusick NFSERR_IO,
43568653Smckusick NFSERR_IO,
43668653Smckusick NFSERR_STALE,
43768653Smckusick NFSERR_BADHANDLE,
43868653Smckusick NFSERR_SERVERFAULT,
43968653Smckusick 0,
44068653Smckusick };
44168653Smckusick
44268653Smckusick static short nfsv3err_fsinfo[] = {
44368653Smckusick NFSERR_STALE,
44468653Smckusick NFSERR_STALE,
44568653Smckusick NFSERR_BADHANDLE,
44668653Smckusick NFSERR_SERVERFAULT,
44768653Smckusick 0,
44868653Smckusick };
44968653Smckusick
45068653Smckusick static short nfsv3err_pathconf[] = {
45168653Smckusick NFSERR_STALE,
45268653Smckusick NFSERR_STALE,
45368653Smckusick NFSERR_BADHANDLE,
45468653Smckusick NFSERR_SERVERFAULT,
45568653Smckusick 0,
45668653Smckusick };
45768653Smckusick
45868653Smckusick static short nfsv3err_commit[] = {
45968653Smckusick NFSERR_IO,
46068653Smckusick NFSERR_IO,
46168653Smckusick NFSERR_STALE,
46268653Smckusick NFSERR_BADHANDLE,
46368653Smckusick NFSERR_SERVERFAULT,
46468653Smckusick 0,
46568653Smckusick };
46668653Smckusick
46768653Smckusick static short *nfsrv_v3errmap[] = {
46868653Smckusick nfsv3err_null,
46968653Smckusick nfsv3err_getattr,
47068653Smckusick nfsv3err_setattr,
47168653Smckusick nfsv3err_lookup,
47268653Smckusick nfsv3err_access,
47368653Smckusick nfsv3err_readlink,
47468653Smckusick nfsv3err_read,
47568653Smckusick nfsv3err_write,
47668653Smckusick nfsv3err_create,
47768653Smckusick nfsv3err_mkdir,
47868653Smckusick nfsv3err_symlink,
47968653Smckusick nfsv3err_mknod,
48068653Smckusick nfsv3err_remove,
48168653Smckusick nfsv3err_rmdir,
48268653Smckusick nfsv3err_rename,
48368653Smckusick nfsv3err_link,
48468653Smckusick nfsv3err_readdir,
48568653Smckusick nfsv3err_readdirplus,
48668653Smckusick nfsv3err_fsstat,
48768653Smckusick nfsv3err_fsinfo,
48868653Smckusick nfsv3err_pathconf,
48968653Smckusick nfsv3err_commit,
49068653Smckusick };
49168653Smckusick
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;
49868653Smckusick extern struct nfsstats nfsstats;
49968653Smckusick extern int nqnfs_piggy[NFS_NPROCS];
50068653Smckusick extern nfstype nfsv2_type[9];
50168653Smckusick extern nfstype nfsv3_type[9];
50268653Smckusick extern struct nfsnodehashhead *nfsnodehashtbl;
50368653Smckusick extern u_long nfsnodehash;
50438420Smckusick
50568653Smckusick #ifdef VFS_LKM
50668653Smckusick struct getfh_args;
50768653Smckusick extern int getfh(struct proc *, struct getfh_args *, int *);
50868653Smckusick struct nfssvc_args;
50968653Smckusick extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
51068653Smckusick #endif
51168653Smckusick
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 *
nfsm_reqh(vp,procid,hsiz,bposp)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 *
nfsm_rpchead(cr,nmflag,procid,auth_type,auth_len,auth_str,verf_len,verf_str,mrest,mrest_len,mbp,xidp)56868653Smckusick nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
56968653Smckusick verf_str, mrest, mrest_len, mbp, xidp)
57052196Smckusick register struct ucred *cr;
57168653Smckusick int nmflag;
57252196Smckusick int procid;
57352196Smckusick int auth_type;
57452196Smckusick int auth_len;
57552196Smckusick char *auth_str;
57668653Smckusick int verf_len;
57768653Smckusick 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);
59268653Smckusick if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
59352196Smckusick MCLGET(mb, M_WAIT);
59468653Smckusick } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
59568653Smckusick MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
59652196Smckusick } else {
59768653Smckusick 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 */
60668653Smckusick 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;
61268653Smckusick if (nmflag & NFSMNT_NQNFS) {
61352196Smckusick *tl++ = txdr_unsigned(NQNFS_PROG);
61468653Smckusick *tl++ = txdr_unsigned(NQNFS_VER3);
61552196Smckusick } else {
61652196Smckusick *tl++ = txdr_unsigned(NFS_PROG);
61768653Smckusick if (nmflag & NFSMNT_NFSV3)
61868653Smckusick *tl++ = txdr_unsigned(NFS_VER3);
61968653Smckusick else
62068653Smckusick *tl++ = txdr_unsigned(NFS_VER2);
62152196Smckusick }
62268653Smckusick if (nmflag & NFSMNT_NFSV3)
62368653Smckusick *tl++ = txdr_unsigned(procid);
62468653Smckusick else
62568653Smckusick *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;
64468653Smckusick 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 };
67068653Smckusick
67168653Smckusick /*
67268653Smckusick * And the verifier...
67368653Smckusick */
67468653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
67568653Smckusick if (verf_str) {
67668653Smckusick *tl++ = txdr_unsigned(RPCAUTH_KERB4);
67768653Smckusick *tl = txdr_unsigned(verf_len);
67868653Smckusick siz = verf_len;
67968653Smckusick while (siz > 0) {
68068653Smckusick if (M_TRAILINGSPACE(mb) == 0) {
68168653Smckusick MGET(mb2, M_WAIT, MT_DATA);
68268653Smckusick if (siz >= MINCLSIZE)
68368653Smckusick MCLGET(mb2, M_WAIT);
68468653Smckusick mb->m_next = mb2;
68568653Smckusick mb = mb2;
68668653Smckusick mb->m_len = 0;
68768653Smckusick bpos = mtod(mb, caddr_t);
68868653Smckusick }
68968653Smckusick i = min(siz, M_TRAILINGSPACE(mb));
69068653Smckusick bcopy(verf_str, bpos, i);
69168653Smckusick mb->m_len += i;
69268653Smckusick verf_str += i;
69368653Smckusick bpos += i;
69468653Smckusick siz -= i;
69568653Smckusick }
69668653Smckusick if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
69768653Smckusick for (i = 0; i < siz; i++)
69868653Smckusick *bpos++ = '\0';
69968653Smckusick mb->m_len += siz;
70068653Smckusick }
70168653Smckusick } else {
70268653Smckusick *tl++ = txdr_unsigned(RPCAUTH_NULL);
70368653Smckusick *tl = 0;
70468653Smckusick }
70552196Smckusick mb->m_next = mrest;
70668653Smckusick 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 */
71568653Smckusick int
nfsm_mbuftouio(mrep,uiop,siz,dpos)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 */
79068653Smckusick int
nfsm_uiotombuf(uiop,mq,siz,bpos)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 */
87868653Smckusick int
nfsm_disct(mdp,dposp,siz,left,cp2)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 */
94168653Smckusick int
nfs_adv(mdp,dposp,offs,left)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 */
96868653Smckusick int
nfsm_strtmbuf(mb,bpos,cp,siz)96938420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz)
97038420Smckusick struct mbuf **mb;
97138420Smckusick char **bpos;
97238420Smckusick char *cp;
97338420Smckusick long siz;
97438420Smckusick {
97568653Smckusick 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 */
103468653Smckusick int
nfs_init(vfsp)103568653Smckusick nfs_init(vfsp)
103668653Smckusick struct vfsconf *vfsp;
103738420Smckusick {
103838420Smckusick register int i;
103938420Smckusick
104068653Smckusick /*
104168653Smckusick * Check to see if major data structures haven't bloated.
104268653Smckusick */
104368653Smckusick if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
104468653Smckusick printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
104568653Smckusick printf("Try reducing NFS_SMALLFH\n");
104668653Smckusick }
104768653Smckusick if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
104868653Smckusick printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
104968653Smckusick printf("Try reducing NFS_MUIDHASHSIZ\n");
105068653Smckusick }
105168653Smckusick if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
105268653Smckusick printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
105368653Smckusick printf("Try reducing NFS_UIDHASHSIZ\n");
105468653Smckusick }
105568653Smckusick if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
105668653Smckusick printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
105768653Smckusick printf("Try unionizing the nu_nickname and nu_flag fields\n");
105868653Smckusick }
105968653Smckusick 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);
106968653Smckusick rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
107038420Smckusick nfs_prog = txdr_unsigned(NFS_PROG);
107168653Smckusick nqnfs_prog = txdr_unsigned(NQNFS_PROG);
107238420Smckusick nfs_true = txdr_unsigned(TRUE);
107338420Smckusick nfs_false = txdr_unsigned(FALSE);
107468653Smckusick nfs_xdrneg1 = txdr_unsigned(-1);
107568653Smckusick nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
107668653Smckusick if (nfs_ticks < 1)
107768653Smckusick 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);
110168653Smckusick nfs_timer(0);
110268653Smckusick 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 */
111968653Smckusick int
nfs_loadattrcache(vpp,mdp,dposp,vaper)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;
112868653Smckusick 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;
113368653Smckusick caddr_t cp2;
113468653Smckusick int error = 0, rdev;
113539494Smckusick struct mbuf *md;
113652196Smckusick enum vtype vtyp;
113752196Smckusick u_short vmode;
113856287Smckusick struct timespec mtime;
113939444Smckusick struct vnode *nvp;
114068653Smckusick quad_t tval;
114168653Smckusick int v3 = NFS_ISV3(vp);
114238420Smckusick
114338420Smckusick md = *mdp;
114468653Smckusick t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
114568653Smckusick if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
114638420Smckusick return (error);
114768653Smckusick fp = (struct nfs_fattr *)cp2;
114868653Smckusick if (v3) {
114968653Smckusick vtyp = nfsv3tov_type(fp->fa_type);
115068653Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode);
115168653Smckusick rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
115268653Smckusick fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
115368653Smckusick fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
115456287Smckusick } else {
115568653Smckusick vtyp = nfsv2tov_type(fp->fa_type);
115668653Smckusick vmode = fxdr_unsigned(u_short, fp->fa_mode);
115768653Smckusick if (vtyp == VNON || vtyp == VREG)
115868653Smckusick vtyp = IFTOVT(vmode);
115968653Smckusick rdev = fxdr_unsigned(long, fp->fa2_rdev);
116068653Smckusick fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
116168653Smckusick
116268653Smckusick /*
116368653Smckusick * Really ugly NFSv2 kludge.
116468653Smckusick */
116568653Smckusick if (vtyp == VCHR && rdev == 0xffffffff)
116668653Smckusick vtyp = VFIFO;
116756287Smckusick }
116868653Smckusick
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) {
117868653Smckusick 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;
118568653Smckusick nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
118668653Smckusick if (nvp) {
118739444Smckusick /*
118851984Smckusick * Discard unneeded vnode, but save its nfsnode.
1189*69606Smckusick * Since the nfsnode does not have a lock, its
1190*69606Smckusick * vnode lock has to be carried over.
119151984Smckusick */
1192*69606Smckusick nvp->v_vnlock = vp->v_vnlock;
1193*69606Smckusick vp->v_vnlock = NULL;
119451984Smckusick nvp->v_data = vp->v_data;
119551984Smckusick vp->v_data = NULL;
119653553Sheideman vp->v_op = spec_vnodeop_p;
119751984Smckusick vrele(vp);
119851984Smckusick vgone(vp);
119951984Smckusick /*
120039444Smckusick * Reinitialize aliased node.
120139444Smckusick */
120239444Smckusick np->n_vnode = nvp;
120351984Smckusick *vpp = vp = nvp;
120439444Smckusick }
120539444Smckusick }
120656287Smckusick np->n_mtime = mtime.ts_sec;
120739444Smckusick }
120838420Smckusick vap = &np->n_vattr;
120952196Smckusick vap->va_type = vtyp;
121052196Smckusick vap->va_mode = (vmode & 07777);
121156287Smckusick vap->va_rdev = (dev_t)rdev;
121256287Smckusick vap->va_mtime = mtime;
121356287Smckusick vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
121468653Smckusick if (v3) {
121568653Smckusick vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
121668653Smckusick vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
121768653Smckusick vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
121868653Smckusick fxdr_hyper(&fp->fa3_size, &vap->va_size);
121968653Smckusick vap->va_blocksize = NFS_FABLKSIZE;
122068653Smckusick fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
122168653Smckusick vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
122268653Smckusick fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
122368653Smckusick fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
122468653Smckusick vap->va_flags = 0;
122568653Smckusick vap->va_filerev = 0;
122656287Smckusick } else {
122768653Smckusick vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
122868653Smckusick vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
122968653Smckusick vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
123068653Smckusick vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
123168653Smckusick vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
123268653Smckusick vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
123368653Smckusick vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
123468653Smckusick fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
123558881Smckusick vap->va_flags = 0;
123668653Smckusick vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
123756287Smckusick vap->va_ctime.ts_nsec = 0;
123868653Smckusick vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
123956287Smckusick vap->va_filerev = 0;
124056287Smckusick }
124157787Smckusick if (vap->va_size != np->n_size) {
124257787Smckusick if (vap->va_type == VREG) {
124357787Smckusick if (np->n_flag & NMODIFIED) {
124457787Smckusick if (vap->va_size < np->n_size)
124557787Smckusick vap->va_size = np->n_size;
124657787Smckusick else
124757787Smckusick np->n_size = vap->va_size;
124857787Smckusick } else
124957787Smckusick np->n_size = vap->va_size;
125057787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size);
125157787Smckusick } else
125257787Smckusick np->n_size = vap->va_size;
125345716Smckusick }
125438420Smckusick np->n_attrstamp = time.tv_sec;
125538884Smacklem if (vaper != NULL) {
125638420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
125753628Smckusick if (np->n_flag & NCHG) {
125868653Smckusick if (np->n_flag & NACC)
125968653Smckusick vaper->va_atime = np->n_atim;
126068653Smckusick if (np->n_flag & NUPD)
126168653Smckusick vaper->va_mtime = np->n_mtim;
126253628Smckusick }
126338884Smacklem }
126438420Smckusick return (0);
126538420Smckusick }
126638420Smckusick
126738420Smckusick /*
126838420Smckusick * Check the time stamp
126938420Smckusick * If the cache is valid, copy contents to *vap and return 0
127038420Smckusick * otherwise return an error
127138420Smckusick */
127268653Smckusick int
nfs_getattrcache(vp,vaper)127357787Smckusick nfs_getattrcache(vp, vaper)
127438420Smckusick register struct vnode *vp;
127557787Smckusick struct vattr *vaper;
127638420Smckusick {
127757787Smckusick register struct nfsnode *np = VTONFS(vp);
127857787Smckusick register struct vattr *vap;
127938420Smckusick
128068653Smckusick if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
128138420Smckusick nfsstats.attrcache_misses++;
128238420Smckusick return (ENOENT);
128338420Smckusick }
128452196Smckusick nfsstats.attrcache_hits++;
128557787Smckusick vap = &np->n_vattr;
128657787Smckusick if (vap->va_size != np->n_size) {
128757787Smckusick if (vap->va_type == VREG) {
128857787Smckusick if (np->n_flag & NMODIFIED) {
128957787Smckusick if (vap->va_size < np->n_size)
129057787Smckusick vap->va_size = np->n_size;
129157787Smckusick else
129257787Smckusick np->n_size = vap->va_size;
129357787Smckusick } else
129457787Smckusick np->n_size = vap->va_size;
129557787Smckusick vnode_pager_setsize(vp, (u_long)np->n_size);
129657787Smckusick } else
129757787Smckusick np->n_size = vap->va_size;
129857787Smckusick }
129957787Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
130053628Smckusick if (np->n_flag & NCHG) {
130168653Smckusick if (np->n_flag & NACC)
130268653Smckusick vaper->va_atime = np->n_atim;
130368653Smckusick if (np->n_flag & NUPD)
130468653Smckusick vaper->va_mtime = np->n_mtim;
130553628Smckusick }
130652196Smckusick return (0);
130738420Smckusick }
130838420Smckusick
130938420Smckusick /*
131052196Smckusick * Set up nameidata for a lookup() call and do it
131138420Smckusick */
131268653Smckusick int
nfs_namei(ndp,fhp,len,slp,nam,mdp,dposp,retdirp,p,kerbflag)131368653Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
131438420Smckusick register struct nameidata *ndp;
131538420Smckusick fhandle_t *fhp;
131638420Smckusick int len;
131752196Smckusick struct nfssvc_sock *slp;
131852196Smckusick struct mbuf *nam;
131938420Smckusick struct mbuf **mdp;
132038420Smckusick caddr_t *dposp;
132168653Smckusick struct vnode **retdirp;
132249739Smckusick struct proc *p;
132368653Smckusick int kerbflag;
132438420Smckusick {
132538420Smckusick register int i, rem;
132638420Smckusick register struct mbuf *md;
132749739Smckusick register char *fromcp, *tocp;
132846514Smckusick struct vnode *dp;
132952315Sheideman int error, rdonly;
133052315Sheideman struct componentname *cnp = &ndp->ni_cnd;
133138420Smckusick
133268653Smckusick *retdirp = (struct vnode *)0;
133352315Sheideman MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
133449739Smckusick /*
133549739Smckusick * Copy the name from the mbuf list to ndp->ni_pnbuf
133649739Smckusick * and set the various ndp fields appropriately.
133749739Smckusick */
133849739Smckusick fromcp = *dposp;
133952315Sheideman tocp = cnp->cn_pnbuf;
134049739Smckusick md = *mdp;
134149739Smckusick rem = mtod(md, caddr_t) + md->m_len - fromcp;
134252315Sheideman cnp->cn_hash = 0;
134349739Smckusick for (i = 0; i < len; i++) {
134449739Smckusick while (rem == 0) {
134549739Smckusick md = md->m_next;
134649739Smckusick if (md == NULL) {
134749739Smckusick error = EBADRPC;
134849739Smckusick goto out;
134942244Smckusick }
135049739Smckusick fromcp = mtod(md, caddr_t);
135149739Smckusick rem = md->m_len;
135238420Smckusick }
135349739Smckusick if (*fromcp == '\0' || *fromcp == '/') {
135468653Smckusick error = EACCES;
135549739Smckusick goto out;
135642244Smckusick }
135752315Sheideman cnp->cn_hash += (unsigned char)*fromcp;
135849739Smckusick *tocp++ = *fromcp++;
135949739Smckusick rem--;
136049739Smckusick }
136149739Smckusick *tocp = '\0';
136249739Smckusick *mdp = md;
136349739Smckusick *dposp = fromcp;
136449739Smckusick len = nfsm_rndup(len)-len;
136549739Smckusick if (len > 0) {
136649739Smckusick if (rem >= len)
136749739Smckusick *dposp += len;
136849739Smckusick else if (error = nfs_adv(mdp, dposp, len, rem))
136949739Smckusick goto out;
137049739Smckusick }
137152315Sheideman ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
137252315Sheideman cnp->cn_nameptr = cnp->cn_pnbuf;
137346514Smckusick /*
137446514Smckusick * Extract and set starting directory.
137546514Smckusick */
137652315Sheideman if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
137768653Smckusick nam, &rdonly, kerbflag))
137849739Smckusick goto out;
137938425Smckusick if (dp->v_type != VDIR) {
138041902Smckusick vrele(dp);
138149739Smckusick error = ENOTDIR;
138249739Smckusick goto out;
138338425Smckusick }
138468653Smckusick VREF(dp);
138568653Smckusick *retdirp = dp;
138646514Smckusick ndp->ni_startdir = dp;
138752196Smckusick if (rdonly)
138852315Sheideman cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
138952196Smckusick else
139052315Sheideman cnp->cn_flags |= NOCROSSMOUNT;
139139345Smckusick /*
139249739Smckusick * And call lookup() to do the real work
139338420Smckusick */
139452315Sheideman cnp->cn_proc = p;
139552315Sheideman if (error = lookup(ndp))
139649739Smckusick goto out;
139749739Smckusick /*
139849739Smckusick * Check for encountering a symbolic link
139949739Smckusick */
140052315Sheideman if (cnp->cn_flags & ISSYMLINK) {
140152315Sheideman if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
140249739Smckusick vput(ndp->ni_dvp);
140349739Smckusick else
140449739Smckusick vrele(ndp->ni_dvp);
140549739Smckusick vput(ndp->ni_vp);
140649739Smckusick ndp->ni_vp = NULL;
140749739Smckusick error = EINVAL;
140849739Smckusick goto out;
140949739Smckusick }
141049739Smckusick /*
141149739Smckusick * Check for saved name request
141249739Smckusick */
141352315Sheideman if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
141452315Sheideman cnp->cn_flags |= HASBUF;
141549739Smckusick return (0);
141649739Smckusick }
141749739Smckusick out:
141852315Sheideman FREE(cnp->cn_pnbuf, M_NAMEI);
141938420Smckusick return (error);
142038420Smckusick }
142138420Smckusick
142238420Smckusick /*
142338420Smckusick * A fiddled version of m_adj() that ensures null fill to a long
142438420Smckusick * boundary and only trims off the back end
142538420Smckusick */
142652196Smckusick void
nfsm_adj(mp,len,nul)142738420Smckusick nfsm_adj(mp, len, nul)
142838420Smckusick struct mbuf *mp;
142938420Smckusick register int len;
143038420Smckusick int nul;
143138420Smckusick {
143238420Smckusick register struct mbuf *m;
143338420Smckusick register int count, i;
143438420Smckusick register char *cp;
143538420Smckusick
143638420Smckusick /*
143738420Smckusick * Trim from tail. Scan the mbuf chain,
143838420Smckusick * calculating its length and finding the last mbuf.
143938420Smckusick * If the adjustment only affects this mbuf, then just
144038420Smckusick * adjust and return. Otherwise, rescan and truncate
144138420Smckusick * after the remaining size.
144238420Smckusick */
144338420Smckusick count = 0;
144438420Smckusick m = mp;
144538420Smckusick for (;;) {
144638420Smckusick count += m->m_len;
144738420Smckusick if (m->m_next == (struct mbuf *)0)
144838420Smckusick break;
144938420Smckusick m = m->m_next;
145038420Smckusick }
145138579Smckusick if (m->m_len > len) {
145238420Smckusick m->m_len -= len;
145338420Smckusick if (nul > 0) {
145438420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul;
145538420Smckusick for (i = 0; i < nul; i++)
145638420Smckusick *cp++ = '\0';
145738420Smckusick }
145838420Smckusick return;
145938420Smckusick }
146038420Smckusick count -= len;
146138420Smckusick if (count < 0)
146238420Smckusick count = 0;
146338420Smckusick /*
146438420Smckusick * Correct length for chain is "count".
146538420Smckusick * Find the mbuf with last data, adjust its length,
146638420Smckusick * and toss data from remaining mbufs on chain.
146738420Smckusick */
146838420Smckusick for (m = mp; m; m = m->m_next) {
146938420Smckusick if (m->m_len >= count) {
147038420Smckusick m->m_len = count;
147138420Smckusick if (nul > 0) {
147238420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul;
147338420Smckusick for (i = 0; i < nul; i++)
147438420Smckusick *cp++ = '\0';
147538420Smckusick }
147638420Smckusick break;
147738420Smckusick }
147838420Smckusick count -= m->m_len;
147938420Smckusick }
148068653Smckusick for (m = m->m_next;m;m = m->m_next)
148138420Smckusick m->m_len = 0;
148238420Smckusick }
148338420Smckusick
148438420Smckusick /*
148568653Smckusick * Make these functions instead of macros, so that the kernel text size
148668653Smckusick * doesn't get too big...
148768653Smckusick */
148868653Smckusick void
nfsm_srvwcc(nfsd,before_ret,before_vap,after_ret,after_vap,mbp,bposp)148968653Smckusick nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
149068653Smckusick struct nfsrv_descript *nfsd;
149168653Smckusick int before_ret;
149268653Smckusick register struct vattr *before_vap;
149368653Smckusick int after_ret;
149468653Smckusick struct vattr *after_vap;
149568653Smckusick struct mbuf **mbp;
149668653Smckusick char **bposp;
149768653Smckusick {
149868653Smckusick register struct mbuf *mb = *mbp, *mb2;
149968653Smckusick register char *bpos = *bposp;
150068653Smckusick register u_long *tl;
150168653Smckusick
150268653Smckusick if (before_ret) {
150368653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
150468653Smckusick *tl = nfs_false;
150568653Smckusick } else {
150668653Smckusick nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
150768653Smckusick *tl++ = nfs_true;
150868653Smckusick txdr_hyper(&(before_vap->va_size), tl);
150968653Smckusick tl += 2;
151068653Smckusick txdr_nfsv3time(&(before_vap->va_mtime), tl);
151168653Smckusick tl += 2;
151268653Smckusick txdr_nfsv3time(&(before_vap->va_ctime), tl);
151368653Smckusick }
151468653Smckusick *bposp = bpos;
151568653Smckusick *mbp = mb;
151668653Smckusick nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
151768653Smckusick }
151868653Smckusick
151968653Smckusick void
nfsm_srvpostopattr(nfsd,after_ret,after_vap,mbp,bposp)152068653Smckusick nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
152168653Smckusick struct nfsrv_descript *nfsd;
152268653Smckusick int after_ret;
152368653Smckusick struct vattr *after_vap;
152468653Smckusick struct mbuf **mbp;
152568653Smckusick char **bposp;
152668653Smckusick {
152768653Smckusick register struct mbuf *mb = *mbp, *mb2;
152868653Smckusick register char *bpos = *bposp;
152968653Smckusick register u_long *tl;
153068653Smckusick register struct nfs_fattr *fp;
153168653Smckusick
153268653Smckusick if (after_ret) {
153368653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
153468653Smckusick *tl = nfs_false;
153568653Smckusick } else {
153668653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
153768653Smckusick *tl++ = nfs_true;
153868653Smckusick fp = (struct nfs_fattr *)tl;
153968653Smckusick nfsm_srvfattr(nfsd, after_vap, fp);
154068653Smckusick }
154168653Smckusick *mbp = mb;
154268653Smckusick *bposp = bpos;
154368653Smckusick }
154468653Smckusick
154568653Smckusick void
nfsm_srvfattr(nfsd,vap,fp)154668653Smckusick nfsm_srvfattr(nfsd, vap, fp)
154768653Smckusick register struct nfsrv_descript *nfsd;
154868653Smckusick register struct vattr *vap;
154968653Smckusick register struct nfs_fattr *fp;
155068653Smckusick {
155168653Smckusick
155268653Smckusick fp->fa_nlink = txdr_unsigned(vap->va_nlink);
155368653Smckusick fp->fa_uid = txdr_unsigned(vap->va_uid);
155468653Smckusick fp->fa_gid = txdr_unsigned(vap->va_gid);
155568653Smckusick if (nfsd->nd_flag & ND_NFSV3) {
155668653Smckusick fp->fa_type = vtonfsv3_type(vap->va_type);
155768653Smckusick fp->fa_mode = vtonfsv3_mode(vap->va_mode);
155868653Smckusick txdr_hyper(&vap->va_size, &fp->fa3_size);
155968653Smckusick txdr_hyper(&vap->va_bytes, &fp->fa3_used);
156068653Smckusick fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
156168653Smckusick fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
156268653Smckusick fp->fa3_fsid.nfsuquad[0] = 0;
156368653Smckusick fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
156468653Smckusick fp->fa3_fileid.nfsuquad[0] = 0;
156568653Smckusick fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
156668653Smckusick txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
156768653Smckusick txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
156868653Smckusick txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
156968653Smckusick } else {
157068653Smckusick fp->fa_type = vtonfsv2_type(vap->va_type);
157168653Smckusick fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
157268653Smckusick fp->fa2_size = txdr_unsigned(vap->va_size);
157368653Smckusick fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
157468653Smckusick if (vap->va_type == VFIFO)
157568653Smckusick fp->fa2_rdev = 0xffffffff;
157668653Smckusick else
157768653Smckusick fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
157868653Smckusick fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
157968653Smckusick fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
158068653Smckusick fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
158168653Smckusick txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
158268653Smckusick txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
158368653Smckusick txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
158468653Smckusick }
158568653Smckusick }
158668653Smckusick
158768653Smckusick /*
158838420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
158938420Smckusick * - look up fsid in mount list (if not found ret error)
159054739Smckusick * - get vp and export rights by calling VFS_FHTOVP()
159154739Smckusick * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
159238420Smckusick * - if not lockflag unlock it with VOP_UNLOCK()
159338420Smckusick */
159468653Smckusick int
nfsrv_fhtovp(fhp,lockflag,vpp,cred,slp,nam,rdonlyp,kerbflag)159568653Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
159638420Smckusick fhandle_t *fhp;
159738420Smckusick int lockflag;
159838420Smckusick struct vnode **vpp;
159938420Smckusick struct ucred *cred;
160052196Smckusick struct nfssvc_sock *slp;
160152196Smckusick struct mbuf *nam;
160252196Smckusick int *rdonlyp;
160368653Smckusick int kerbflag;
160438420Smckusick {
160569424Smckusick struct proc *p = curproc; /* XXX */
160638420Smckusick register struct mount *mp;
160752196Smckusick register struct nfsuid *uidp;
160857787Smckusick register int i;
160954739Smckusick struct ucred *credanon;
161054739Smckusick int error, exflags;
161138420Smckusick
161252196Smckusick *vpp = (struct vnode *)0;
161368653Smckusick mp = vfs_getvfs(&fhp->fh_fsid);
161468653Smckusick if (!mp)
161538420Smckusick return (ESTALE);
161668653Smckusick error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
161768653Smckusick if (error)
161854739Smckusick return (error);
161952196Smckusick /*
162052196Smckusick * Check/setup credentials.
162152196Smckusick */
162254739Smckusick if (exflags & MNT_EXKERB) {
162368653Smckusick if (!kerbflag) {
162457787Smckusick vput(*vpp);
162568653Smckusick return (NFSERR_AUTHERR | AUTH_TOOWEAK);
162657787Smckusick }
162768653Smckusick } else if (kerbflag) {
162868653Smckusick vput(*vpp);
162968653Smckusick return (NFSERR_AUTHERR | AUTH_TOOWEAK);
163057787Smckusick } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
163157787Smckusick cred->cr_uid = credanon->cr_uid;
163257787Smckusick for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
163357787Smckusick cred->cr_groups[i] = credanon->cr_groups[i];
163467567Smckusick cred->cr_ngroups = i;
163557787Smckusick }
163654739Smckusick if (exflags & MNT_EXRDONLY)
163752196Smckusick *rdonlyp = 1;
163845282Smckusick else
163952196Smckusick *rdonlyp = 0;
164052196Smckusick if (!lockflag)
164169424Smckusick VOP_UNLOCK(*vpp, 0, p);
164252196Smckusick return (0);
164345282Smckusick }
164454988Smckusick
164554988Smckusick /*
164654988Smckusick * This function compares two net addresses by family and returns TRUE
164754988Smckusick * if they are the same host.
164854988Smckusick * If there is any doubt, return FALSE.
164954988Smckusick * The AF_INET family is handled as a special case so that address mbufs
165054988Smckusick * don't need to be saved to store "struct in_addr", which is only 4 bytes.
165154988Smckusick */
165268653Smckusick int
netaddr_match(family,haddr,nam)165356363Smckusick netaddr_match(family, haddr, nam)
165454988Smckusick int family;
165554988Smckusick union nethostaddr *haddr;
165654988Smckusick struct mbuf *nam;
165754988Smckusick {
165854988Smckusick register struct sockaddr_in *inetaddr;
165954988Smckusick
166054988Smckusick switch (family) {
166154988Smckusick case AF_INET:
166254988Smckusick inetaddr = mtod(nam, struct sockaddr_in *);
166356363Smckusick if (inetaddr->sin_family == AF_INET &&
166456363Smckusick inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
166554988Smckusick return (1);
166654988Smckusick break;
166754988Smckusick #ifdef ISO
166854988Smckusick case AF_ISO:
166956363Smckusick {
167056363Smckusick register struct sockaddr_iso *isoaddr1, *isoaddr2;
167156363Smckusick
167254988Smckusick isoaddr1 = mtod(nam, struct sockaddr_iso *);
167354988Smckusick isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
167456363Smckusick if (isoaddr1->siso_family == AF_ISO &&
167556363Smckusick isoaddr1->siso_nlen > 0 &&
167654988Smckusick isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
167754988Smckusick SAME_ISOADDR(isoaddr1, isoaddr2))
167854988Smckusick return (1);
167954988Smckusick break;
168056363Smckusick }
168154988Smckusick #endif /* ISO */
168254988Smckusick default:
168354988Smckusick break;
168454988Smckusick };
168554988Smckusick return (0);
168654988Smckusick }
168768653Smckusick
168868653Smckusick static nfsuint64 nfs_nullcookie = { 0, 0 };
168968653Smckusick /*
169068653Smckusick * This function finds the directory cookie that corresponds to the
169168653Smckusick * logical byte offset given.
169268653Smckusick */
169368653Smckusick nfsuint64 *
nfs_getcookie(np,off,add)169468653Smckusick nfs_getcookie(np, off, add)
169568653Smckusick register struct nfsnode *np;
169668653Smckusick off_t off;
169768653Smckusick int add;
169868653Smckusick {
169968653Smckusick register struct nfsdmap *dp, *dp2;
170068653Smckusick register int pos;
170168653Smckusick
170268653Smckusick pos = off / NFS_DIRBLKSIZ;
170368653Smckusick if (pos == 0) {
170468653Smckusick #ifdef DIAGNOSTIC
170568653Smckusick if (add)
170668653Smckusick panic("nfs getcookie add at 0");
170768653Smckusick #endif
170868653Smckusick return (&nfs_nullcookie);
170968653Smckusick }
171068653Smckusick pos--;
171168653Smckusick dp = np->n_cookies.lh_first;
171268653Smckusick if (!dp) {
171368653Smckusick if (add) {
171468653Smckusick MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
171568653Smckusick M_NFSDIROFF, M_WAITOK);
171668653Smckusick dp->ndm_eocookie = 0;
171768653Smckusick LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
171868653Smckusick } else
171968653Smckusick return ((nfsuint64 *)0);
172068653Smckusick }
172168653Smckusick while (pos >= NFSNUMCOOKIES) {
172268653Smckusick pos -= NFSNUMCOOKIES;
172368653Smckusick if (dp->ndm_list.le_next) {
172468653Smckusick if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
172568653Smckusick pos >= dp->ndm_eocookie)
172668653Smckusick return ((nfsuint64 *)0);
172768653Smckusick dp = dp->ndm_list.le_next;
172868653Smckusick } else if (add) {
172968653Smckusick MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
173068653Smckusick M_NFSDIROFF, M_WAITOK);
173168653Smckusick dp2->ndm_eocookie = 0;
173268653Smckusick LIST_INSERT_AFTER(dp, dp2, ndm_list);
173368653Smckusick dp = dp2;
173468653Smckusick } else
173568653Smckusick return ((nfsuint64 *)0);
173668653Smckusick }
173768653Smckusick if (pos >= dp->ndm_eocookie) {
173868653Smckusick if (add)
173968653Smckusick dp->ndm_eocookie = pos + 1;
174068653Smckusick else
174168653Smckusick return ((nfsuint64 *)0);
174268653Smckusick }
174368653Smckusick return (&dp->ndm_cookies[pos]);
174468653Smckusick }
174568653Smckusick
174668653Smckusick /*
174768653Smckusick * Invalidate cached directory information, except for the actual directory
174868653Smckusick * blocks (which are invalidated separately).
174968653Smckusick * Done mainly to avoid the use of stale offset cookies.
175068653Smckusick */
175168653Smckusick void
nfs_invaldir(vp)175268653Smckusick nfs_invaldir(vp)
175368653Smckusick register struct vnode *vp;
175468653Smckusick {
175568653Smckusick register struct nfsnode *np = VTONFS(vp);
175668653Smckusick
175768653Smckusick #ifdef DIAGNOSTIC
175868653Smckusick if (vp->v_type != VDIR)
175968653Smckusick panic("nfs: invaldir not dir");
176068653Smckusick #endif
176168653Smckusick np->n_direofoffset = 0;
176268653Smckusick np->n_cookieverf.nfsuquad[0] = 0;
176368653Smckusick np->n_cookieverf.nfsuquad[1] = 0;
176468653Smckusick if (np->n_cookies.lh_first)
176568653Smckusick np->n_cookies.lh_first->ndm_eocookie = 0;
176668653Smckusick }
176768653Smckusick
176868653Smckusick /*
176968653Smckusick * The write verifier has changed (probably due to a server reboot), so all
177068653Smckusick * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
177168653Smckusick * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
177268653Smckusick * flag. Once done the new write verifier can be set for the mount point.
177368653Smckusick */
177468653Smckusick void
nfs_clearcommit(mp)177568653Smckusick nfs_clearcommit(mp)
177668653Smckusick struct mount *mp;
177768653Smckusick {
177868653Smckusick register struct vnode *vp, *nvp;
177968653Smckusick register struct buf *bp, *nbp;
178068653Smckusick int s;
178168653Smckusick
178268653Smckusick s = splbio();
178368653Smckusick loop:
178468653Smckusick for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
178568653Smckusick if (vp->v_mount != mp) /* Paranoia */
178668653Smckusick goto loop;
178768653Smckusick nvp = vp->v_mntvnodes.le_next;
178868653Smckusick for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
178968653Smckusick nbp = bp->b_vnbufs.le_next;
179068653Smckusick if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
179168653Smckusick == (B_DELWRI | B_NEEDCOMMIT))
179268653Smckusick bp->b_flags &= ~B_NEEDCOMMIT;
179368653Smckusick }
179468653Smckusick }
179568653Smckusick splx(s);
179668653Smckusick }
179768653Smckusick
179868653Smckusick /*
179968653Smckusick * Map errnos to NFS error numbers. For Version 3 also filter out error
180068653Smckusick * numbers not specified for the associated procedure.
180168653Smckusick */
180268653Smckusick int
nfsrv_errmap(nd,err)180368653Smckusick nfsrv_errmap(nd, err)
180468653Smckusick struct nfsrv_descript *nd;
180568653Smckusick register int err;
180668653Smckusick {
180768653Smckusick register short *defaulterrp, *errp;
180868653Smckusick
180968653Smckusick if (nd->nd_flag & ND_NFSV3) {
181068653Smckusick if (nd->nd_procnum <= NFSPROC_COMMIT) {
181168653Smckusick errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
181268653Smckusick while (*++errp) {
181368653Smckusick if (*errp == err)
181468653Smckusick return (err);
181568653Smckusick else if (*errp > err)
181668653Smckusick break;
181768653Smckusick }
181868653Smckusick return ((int)*defaulterrp);
181968653Smckusick } else
182068653Smckusick return (err & 0xffff);
182168653Smckusick }
182268653Smckusick if (err <= ELAST)
182368653Smckusick return ((int)nfsrv_v2errmap[err - 1]);
182468653Smckusick return (NFSERR_IO);
182568653Smckusick }
1826