aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Rabson <dfr@FreeBSD.org>1995-06-27 11:07:30 +0000
committerDoug Rabson <dfr@FreeBSD.org>1995-06-27 11:07:30 +0000
commita62dc4065454b3af8bde3af9f005db2c4d802fec (patch)
tree372bad41f8c547f40d0826ed596c53dc772ab986
parent82aaeb09ad6963c8e01e332d734ea0a69b66ed2e (diff)
downloadsrc-a62dc4065454b3af8bde3af9f005db2c4d802fec.tar.gz
src-a62dc4065454b3af8bde3af9f005db2c4d802fec.zip
Changes to support version 3 of the NFS protocol.
The version 2 support has been tested (client+server) against FreeBSD-2.0, IRIX 5.3 and FreeBSD-current (using a loopback mount). The version 2 support is stable AFAIK. The version 3 support has been tested with a loopback mount and minimally against an IRIX 5.3 server. It needs more testing and may have problems. I have patched amd to support the new variable length filehandles although it will still only use version 2 of the protocol. Before booting a kernel with these changes, nfs clients will need to at least build and install /usr/sbin/mount_nfs. Servers will need to build and install /usr/sbin/mountd. NFS diskless support is untested. Obtained from: Rick Macklem <rick@snowhite.cis.uoguelph.ca>
Notes
Notes: svn path=/head/; revision=9336
-rw-r--r--include/rpcsvc/bootparam_prot.x2
-rw-r--r--sbin/mount_nfs/mount_nfs.871
-rw-r--r--sbin/mount_nfs/mount_nfs.c285
-rw-r--r--sbin/mountd/exports.510
-rw-r--r--sbin/mountd/mountd.817
-rw-r--r--sbin/mountd/mountd.c247
-rw-r--r--sbin/nfsd/nfsd.83
-rw-r--r--sbin/nfsd/nfsd.c110
-rw-r--r--sbin/nfsiod/nfsiod.c4
-rw-r--r--sys/nfs/nfs.h279
-rw-r--r--sys/nfs/nfs_bio.c292
-rw-r--r--sys/nfs/nfs_common.c1035
-rw-r--r--sys/nfs/nfs_common.h333
-rw-r--r--sys/nfs/nfs_node.c130
-rw-r--r--sys/nfs/nfs_nqlease.c293
-rw-r--r--sys/nfs/nfs_serv.c2904
-rw-r--r--sys/nfs/nfs_socket.c518
-rw-r--r--sys/nfs/nfs_srvcache.c50
-rw-r--r--sys/nfs/nfs_subs.c1035
-rw-r--r--sys/nfs/nfs_syscalls.c571
-rw-r--r--sys/nfs/nfs_vfsops.c244
-rw-r--r--sys/nfs/nfs_vnops.c2318
-rw-r--r--sys/nfs/nfsdiskless.h34
-rw-r--r--sys/nfs/nfsm_subs.h333
-rw-r--r--sys/nfs/nfsmount.h15
-rw-r--r--sys/nfs/nfsnode.h116
-rw-r--r--sys/nfs/nfsproto.h441
-rw-r--r--sys/nfs/nfsrtt.h3
-rw-r--r--sys/nfs/nfsrvcache.h4
-rw-r--r--sys/nfs/nfsv2.h361
-rw-r--r--sys/nfs/nqnfs.h33
-rw-r--r--sys/nfs/rpcv2.h49
-rw-r--r--sys/nfs/xdr_subs.h32
-rw-r--r--sys/nfsclient/nfs.h279
-rw-r--r--sys/nfsclient/nfs_bio.c292
-rw-r--r--sys/nfsclient/nfs_nfsiod.c571
-rw-r--r--sys/nfsclient/nfs_node.c130
-rw-r--r--sys/nfsclient/nfs_socket.c518
-rw-r--r--sys/nfsclient/nfs_subs.c1035
-rw-r--r--sys/nfsclient/nfs_vfsops.c244
-rw-r--r--sys/nfsclient/nfs_vnops.c2318
-rw-r--r--sys/nfsclient/nfsargs.h279
-rw-r--r--sys/nfsclient/nfsdiskless.h34
-rw-r--r--sys/nfsclient/nfsm_subs.h333
-rw-r--r--sys/nfsclient/nfsmount.h15
-rw-r--r--sys/nfsclient/nfsnode.h116
-rw-r--r--sys/nfsclient/nfsstats.h279
-rw-r--r--sys/nfsserver/nfs.h279
-rw-r--r--sys/nfsserver/nfs_serv.c2904
-rw-r--r--sys/nfsserver/nfs_srvcache.c50
-rw-r--r--sys/nfsserver/nfs_srvsock.c518
-rw-r--r--sys/nfsserver/nfs_srvsubs.c1035
-rw-r--r--sys/nfsserver/nfs_syscalls.c571
-rw-r--r--sys/nfsserver/nfsm_subs.h333
-rw-r--r--sys/nfsserver/nfsproto.h441
-rw-r--r--sys/nfsserver/nfsrvcache.h4
-rw-r--r--sys/nfsserver/nfsrvstats.h279
-rw-r--r--sys/sys/mount.h35
-rw-r--r--usr.bin/fstat/fstat.c2
-rw-r--r--usr.bin/nfsstat/nfsstat.c90
-rw-r--r--usr.bin/showmount/showmount.89
-rw-r--r--usr.bin/showmount/showmount.c12
-rw-r--r--usr.sbin/amd/amd/afs_ops.c5
-rw-r--r--usr.sbin/amd/amd/nfs_ops.c5
-rw-r--r--usr.sbin/amd/config/os-bsd44.h7
-rw-r--r--usr.sbin/mountd/exports.510
-rw-r--r--usr.sbin/mountd/mountd.817
-rw-r--r--usr.sbin/mountd/mountd.c247
-rw-r--r--usr.sbin/nfsd/nfsd.83
-rw-r--r--usr.sbin/nfsd/nfsd.c110
-rw-r--r--usr.sbin/pstat/pstat.c2
71 files changed, 18919 insertions, 6664 deletions
diff --git a/include/rpcsvc/bootparam_prot.x b/include/rpcsvc/bootparam_prot.x
index a6d4f0ee022f..249ed8ab90af 100644
--- a/include/rpcsvc/bootparam_prot.x
+++ b/include/rpcsvc/bootparam_prot.x
@@ -44,8 +44,6 @@
%#include <sys/param.h>
%#include <sys/syslimits.h>
%#include <sys/ucred.h>
-%#include <nfs/nfsv2.h>
-%#include <nfs/nfs.h>
#else
%#ifndef lint
%/*static char sccsid[] = "from: @(#)bootparam_prot.x 1.2 87/06/24 Copyr 1987 Sun Micro";*/
diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index 0209b49f3854..8ee10f318250 100644
--- a/sbin/mount_nfs/mount_nfs.8
+++ b/sbin/mount_nfs/mount_nfs.8
@@ -39,8 +39,9 @@
.Nd mount nfs file systems
.Sh SYNOPSIS
.Nm mount_nfs
-.Op Fl KMPTbcdiklqs
+.Op Fl 3KPTUbcdilqs
.Op Fl D Ar deadthresh
+.Op Fl I Ar readdirsize
.Op Fl L Ar leaseterm
.Op Fl R Ar retrycnt
.Op Fl a Ar maxreadahead
@@ -63,10 +64,14 @@ on to the file system tree at the point
.Ar node.
This command is normally executed by
.Xr mount 8 .
-It implements the mount protocol as described in RFC 1094, Appendix A.
+It implements the mount protocol as described in RFC 1094, Appendix A and
+.%T "NFS: Network File System Version 3 Protocol Specification" ,
+Appendix I.
.Pp
The options are:
.Bl -tag -width indent
+.It Fl 3
+Use the NFS Version 3 protocol (Version 2 is the default).
.It Fl D
Used with NQNFS to set the
.Dq "dead server threshold"
@@ -80,23 +85,27 @@ Values may be set in the range of 1 - 9, with 9 referring to an
(i.e. never assume cached data still valid).
This option is not generally recommended and is really an experimental
feature.
+.It Fl I
+Set the readdir read size to the specified value. The value should normally
+be a multiple of DIRBLKSIZ that is <= the read size for the mount.
.It Fl K
Pass Kerberos authenticators to the server for client-to-server
user-credential mapping.
-This may only be used over TCP mounts between 4.4BSD clients and servers.
+This requires that the kernel be built with the NFSKERB option.
+(Refer to the INTERNET-DRAFT titled
+.%T "Authentication Mechanisms for ONC RPC" ,
+for more information.)
.It Fl L
Used with NQNFS to set the lease term to the specified number of seconds.
Only use this argument for mounts with a large round trip delay.
Values are normally in the 10-30 second range.
-.It Fl M
-Assume that other clients are not writing a file concurrently with this client.
-This implements a slightly less strict consistency criteria than 4.3BSD-Reno
-did, that is more in line with most commercial client implementations.
-This is recommended for servers that do not support leasing.
.It Fl P
Use a reserved socket port number.
This is useful for mounting servers that require clients to use a
-reserved port number.
+reserved port number on the mistaken belief that this makes NFS
+more secure. (For the rare case where the client has a trusted root account
+but untrusworthy users and the network cables are in secure areas this does
+help, but for normal desktop clients this does not apply.)
.It Fl R
Set the retry count for doing the mount to the specified value.
.It Fl T
@@ -104,11 +113,15 @@ Use TCP transport instead of UDP.
This is recommended for servers that are not on the same LAN cable as
the client.
(NB: This is NOT supported by most non-BSD servers.)
+.It Fl U
+Force the mount protocol to use UDP transport, even for TCP NFS mounts.
+(Necessary for some old BSD servers.)
.It Fl a
Set the read-ahead count to the specified value.
This may be in the range of 0 - 4, and determines how many blocks
will be read ahead when a large file is being read sequentially.
-This is recommended for mounts with a large bandwidth * delay product.
+Trying a value greater than 1 for this is suggested for
+mounts with a large bandwidth * delay product.
.It Fl b
If an initial attempt to contact the server fails, fork off a child to keep
trying the mount in the background.
@@ -119,10 +132,12 @@ where the filesystem mount is not critical to multiuser operation.
For UDP mount points, do not do a
.Xr connect 2 .
This must be used for servers that do not reply to requests from the
-standard port number.
+standard NFS port number 2049.
.It Fl d
-Do not estimate retransmit timeout dynamically.
-This may be useful for UDP mounts that exhibit high retry rates.
+Turn off the dynamic retransmit timeout estimator.
+This may be useful for UDP mounts that exhibit high retry rates,
+since it is possible that the dynamically estimated timeout interval is too
+short.
.It Fl g
Set the maximum size of the group list for the credentials to the
specified value.
@@ -134,20 +149,15 @@ point.
Make the mount interruptible, which implies that file system calls that
are delayed due to an unresponsive server will fail with EINTR when a
termination signal is posted for the process.
-.It Fl k
-Used with NQNFS to specify
-.Dq get a lease
-for the file name being looked up.
-This is recommended unless the server is complaining about excessive
-lease load.
.It Fl l
-Used with NQNFS to specify that the \fBReaddir_and_Lookup\fR RPC should
+Used with NQNFS and NFSV3 to specify that the \fBReaddirPlus\fR RPC should
be used.
This option reduces RPC traffic for cases such as
.Dq "ls -l" ,
-but increases the lease load on the server.
-This is recommended unless the server is complaining about excessive
-lease load.
+but tends to flood the attribute and name caches with prefetched entries.
+Try this option and see whether performance improves or degrades. Probably
+most useful for client to server network interconnects with a large bandwidth
+times delay product.
.It Fl m
Set the Kerberos realm to the string argument.
Used with the
@@ -167,12 +177,16 @@ Use specified port number for NFS requests.
The default is to query the portmapper for the NFS port.
.El
.It Fl q
-Use the leasing extensions to the protocol to maintain cache consistency.
-This protocol, referred to as Not Quite Nfs (NQNFS),
-is only supported by 4.4BSD servers.
+Use the leasing extensions to the NFS Version 3 protocol to maintain cache consistency.
+This protocol Version 2, referred to as Not Quite Nfs (NQNFS),
+is only supported by this updated release of NFS code.
+(It is not backwards compatible with the release of NQNFS that went out on
+4.4BSD-Lite. To interoperate with a 4.4BSD-Lite NFS system you will have to
+avoid this option until you have had an oppurtunity to upgrade the NFS code
+on all your 4.4BSD-Lite based systems.)
.It Fl r
Set the read data size to the specified value.
-It should be a power of 2 greater than or equal to 1024.
+It should normally be a power of 2 greater than or equal to 1024.
This should be used for UDP mounts when the
.Dq "fragments dropped due to timeout"
value is getting large while actively using a mount point.
@@ -197,6 +211,9 @@ Try increasing the interval if
.Xr nfsstat 1
shows high retransmit rates while the file system is active or reducing the
value if there is a low retransmit rate but long response delay observed.
+(Normally, the -d option should be specified when using this option to manually
+tune the timeout
+interval.)
.It Fl w
Set the write data size to the specified value.
Ditto the comments w.r.t. the
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c
index 9aa15ceec7c5..ddba2741872c 100644
--- a/sbin/mount_nfs/mount_nfs.c
+++ b/sbin/mount_nfs/mount_nfs.c
@@ -59,16 +59,16 @@ static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) 3/27/94";
#include <netiso/iso.h>
#endif
-#ifdef KERBEROS
+#ifdef NFSKERB
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#endif
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
-#define KERNEL
+#include <nfs/nfsproto.h>
+#define _KERNEL
#include <nfs/nfs.h>
-#undef KERNEL
+#undef _KERNEL
#include <nfs/nqnfs.h>
#include <arpa/inet.h>
@@ -86,14 +86,15 @@ static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) 3/27/94";
#include "mntopts.h"
+#ifdef __FreeBSD__
#define ALTF_BG 0x1
#define ALTF_NOCONN 0x2
#define ALTF_DUMBTIMR 0x4
#define ALTF_INTR 0x8
#define ALTF_KERB 0x10
-#define ALTF_NQLOOKLSE 0x20
-#define ALTF_RDIRALOOK 0x40
-#define ALTF_MYWRITE 0x80
+#define ALTF_NFSV3 0x20
+#define ALTF_RDIRPLUS 0x40
+#define ALTF_MNTUDP 0x80
#define ALTF_RESVPORT 0x100
#define ALTF_SEQPACKET 0x200
#define ALTF_NQNFS 0x400
@@ -109,12 +110,12 @@ struct mntopt mopts[] = {
{ "conn", 1, ALTF_NOCONN, 1 },
{ "dumbtimer", 0, ALTF_DUMBTIMR, 1 },
{ "intr", 0, ALTF_INTR, 1 },
-#ifdef KERBEROS
+#ifdef NFSKERB
{ "kerb", 0, ALTF_KERB, 1 },
#endif
- { "nqlooklease", 0, ALTF_NQLOOKLSE, 1 },
- { "rdiralook", 0, ALTF_RDIRALOOK, 1 },
- { "mywrite", 0, ALTF_MYWRITE, 1 },
+ { "nfsv3", 0, ALTF_NFSV3, 1 },
+ { "rdirplus", 0, ALTF_RDIRPLUS, 1 },
+ { "mntudp", 0, ALTF_MNTUDP, 1 },
{ "resvport", 0, ALTF_RESVPORT, 1 },
#ifdef ISO
{ "seqpacket", 0, ALTF_SEQPACKET, 1 },
@@ -125,17 +126,27 @@ struct mntopt mopts[] = {
{ "port=", 0, ALTF_PORT, 1 },
{ NULL }
};
+#else
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ MOPT_FORCE,
+ MOPT_UPDATE,
+ { NULL }
+};
+#endif
struct nfs_args nfsdefargs = {
(struct sockaddr *)0,
sizeof (struct sockaddr_in),
SOCK_DGRAM,
0,
- (nfsv2fh_t *)0,
+ (u_char *)0,
+ 0,
0,
NFS_WSIZE,
NFS_RSIZE,
- NFS_TIMEO,
+ NFS_READDIRSIZE,
+ 10,
NFS_RETRANS,
NFS_MAXGRPS,
NFS_DEFRAHEAD,
@@ -145,20 +156,34 @@ struct nfs_args nfsdefargs = {
};
struct nfhret {
- u_long stat;
- nfsv2fh_t nfh;
+ u_long stat;
+ long vers;
+ long auth;
+ long fhsize;
+ u_char nfh[NFSX_V3FHMAX];
};
#define DEF_RETRY 10000
#define BGRND 1
#define ISBGRND 2
int retrycnt = DEF_RETRY;
int opflags = 0;
+int nfsproto = IPPROTO_UDP;
+int mnttcp_ok = 1;
u_short port_no = 0;
-#ifdef KERBEROS
+#ifdef NFSKERB
char inst[INST_SZ];
char realm[REALM_SZ];
-KTEXT_ST kt;
+struct {
+ u_long kind;
+ KTEXT_ST kt;
+} ktick;
+struct nfsrpc_nickverf kverf;
+struct nfsrpc_fullblock kin, kout;
+NFSKERBKEY_T kivec;
+CREDENTIALS kcr;
+struct timeval ktv;
+NFSKERBKEYSCHED_T kerb_keysched;
#endif
int getnfsargs __P((char *, struct nfs_args *));
@@ -182,14 +207,17 @@ main(argc, argv)
int mntflags, altflags, i, nfssvc_flag, num;
char *name, *p, *spec;
struct vfsconf *vfc;
-#ifdef KERBEROS
+#ifdef NFSKERB
uid_t last_ruid;
-#endif
-#ifdef KERBEROS
last_ruid = -1;
(void)strcpy(realm, KRB_REALM);
-#endif
+ if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF ||
+ sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK ||
+ ((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED ||
+ ((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED)
+ fprintf(stderr, "Yikes! NFSKERB structs not packed!!\n");
+#endif /* NFSKERB */
retrycnt = DEF_RETRY;
mntflags = 0;
@@ -197,8 +225,11 @@ main(argc, argv)
nfsargs = nfsdefargs;
nfsargsp = &nfsargs;
while ((c = getopt(argc, argv,
- "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF)
+ "3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != EOF)
switch (c) {
+ case '3':
+ nfsargsp->flags |= NFSMNT_NFSV3;
+ break;
case 'a':
num = strtol(optarg, &p, 10);
if (*p || num < 0)
@@ -226,21 +257,27 @@ main(argc, argv)
num = strtol(optarg, &p, 10);
if (*p || num <= 0)
errx(1, "illegal -g value -- %s", optarg);
+#ifdef __FreeBSD__
set_rpc_maxgrouplist(num);
+#endif
nfsargsp->maxgrouplist = num;
nfsargsp->flags |= NFSMNT_MAXGRPS;
break;
+ case 'I':
+ num = strtol(optarg, &p, 10);
+ if (*p || num <= 0)
+ errx(1, "illegal -I value -- %s", optarg);
+ nfsargsp->readdirsize = num;
+ nfsargsp->flags |= NFSMNT_READDIRSIZE;
+ break;
case 'i':
nfsargsp->flags |= NFSMNT_INT;
break;
-#ifdef KERBEROS
+#ifdef NFSKERB
case 'K':
nfsargsp->flags |= NFSMNT_KERB;
break;
#endif
- case 'k':
- nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
- break;
case 'L':
num = strtol(optarg, &p, 10);
if (*p || num < 2)
@@ -249,18 +286,16 @@ main(argc, argv)
nfsargsp->flags |= NFSMNT_LEASETERM;
break;
case 'l':
- nfsargsp->flags |= NFSMNT_RDIRALOOK;
+ nfsargsp->flags |= NFSMNT_RDIRPLUS;
break;
- case 'M':
- nfsargsp->flags |= NFSMNT_MYWRITE;
- break;
-#ifdef KERBEROS
+#ifdef NFSKERB
case 'm':
(void)strncpy(realm, optarg, REALM_SZ - 1);
realm[REALM_SZ - 1] = '\0';
break;
#endif
case 'o':
+#ifdef __FreeBSD__
getmntopts(optarg, mopts, &mntflags, &altflags);
if(altflags & ALTF_BG)
opflags |= BGRND;
@@ -270,16 +305,16 @@ main(argc, argv)
nfsargsp->flags |= NFSMNT_DUMBTIMR;
if(altflags & ALTF_INTR)
nfsargsp->flags |= NFSMNT_INT;
-#ifdef KERBEROS
+#ifdef NFSKERB
if(altflags & ALTF_KERB)
nfsargsp->flags |= NFSMNT_KERB;
#endif
- if(altflags & ALTF_NQLOOKLSE)
- nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
- if(altflags & ALTF_RDIRALOOK)
- nfsargsp->flags |= NFSMNT_RDIRALOOK;
- if(altflags & ALTF_MYWRITE)
- nfsargsp->flags |= NFSMNT_MYWRITE;
+ if(altflags & ALTF_NFSV3)
+ nfsargsp->flags |= NFSMNT_NFSV3;
+ if(altflags & ALTF_RDIRPLUS)
+ nfsargsp->flags |= NFSMNT_RDIRPLUS;
+ if(altflags & ALTF_MNTUDP)
+ mnttcp_ok = 0;
if(altflags & ALTF_RESVPORT)
nfsargsp->flags |= NFSMNT_RESVPORT;
#ifdef ISO
@@ -287,14 +322,19 @@ main(argc, argv)
nfsargsp->sotype = SOCK_SEQPACKET;
#endif
if(altflags & ALTF_NQNFS)
- nfsargsp->flags |= NFSMNT_NQNFS;
+ nfsargsp->flags |= (NFSMNT_NQNFS|NFSMNT_NFSV3);
if(altflags & ALTF_SOFT)
nfsargsp->flags |= NFSMNT_SOFT;
- if(altflags & ALTF_TCP)
+ if(altflags & ALTF_TCP) {
nfsargsp->sotype = SOCK_STREAM;
+ nfsproto = IPPROTO_TCP;
+ }
if(altflags & ALTF_PORT)
port_no = atoi(strstr(optarg, "port=") + 5);
altflags = 0;
+#else
+ getmntopts(optarg, mopts, &mntflags);
+#endif
break;
case 'P':
nfsargsp->flags |= NFSMNT_RESVPORT;
@@ -305,7 +345,7 @@ main(argc, argv)
break;
#endif
case 'q':
- nfsargsp->flags |= NFSMNT_NQNFS;
+ nfsargsp->flags |= (NFSMNT_NQNFS | NFSMNT_NFSV3);
break;
case 'R':
num = strtol(optarg, &p, 10);
@@ -325,6 +365,7 @@ main(argc, argv)
break;
case 'T':
nfsargsp->sotype = SOCK_STREAM;
+ nfsproto = IPPROTO_TCP;
break;
case 't':
num = strtol(optarg, &p, 10);
@@ -347,6 +388,9 @@ main(argc, argv)
nfsargsp->retrans = num;
nfsargsp->flags |= NFSMNT_RETRANS;
break;
+ case 'U':
+ mnttcp_ok = 0;
+ break;
default:
usage();
break;
@@ -363,6 +407,7 @@ main(argc, argv)
if (!getnfsargs(spec, nfsargsp))
exit(1);
+#ifdef __FreeBSD__
vfc = getvfsbyname("nfs");
if(!vfc && vfsisloadable("nfs")) {
if(vfsload("nfs"))
@@ -372,6 +417,9 @@ main(argc, argv)
}
if (mount(vfc ? vfc->vfc_index : MOUNT_NFS, name, mntflags, nfsargsp))
+#else
+ if (mount(MOUNT_NFS, name, mntflags, nfsargsp))
+#endif
err(1, "%s", name);
if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
if ((opflags & ISBGRND) == 0) {
@@ -396,13 +444,18 @@ main(argc, argv)
}
nfssvc_flag =
NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
-#ifdef KERBEROS
+#ifdef NFSKERB
/*
* Set up as ncd_authuid for the kerberos call.
* Must set ruid to ncd_authuid and reset the
* ticket name iff ncd_authuid is not the same
* as last time, so that the right ticket file
* is found.
+ * Get the Kerberos credential structure so that
+ * we have the seesion key and get a ticket for
+ * this uid.
+ * For more info see the IETF Draft "Authentication
+ * in ONC RPC".
*/
if (ncd.ncd_authuid != last_ruid) {
char buf[512];
@@ -411,15 +464,62 @@ main(argc, argv)
krb_set_tkt_string(buf);
last_ruid = ncd.ncd_authuid;
}
- if (krb_mk_req(&kt, "rcmd", inst, realm, 0) ==
- KSUCCESS &&
- kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) {
- ncd.ncd_authtype = RPCAUTH_NQNFS;
- ncd.ncd_authlen = kt.length;
- ncd.ncd_authstr = (char *)kt.dat;
- nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
+ setreuid(ncd.ncd_authuid, 0);
+ kret = krb_get_cred(NFS_KERBSRV, inst, realm, &kcr);
+ if (kret == RET_NOTKT) {
+ kret = get_ad_tkt(NFS_KERBSRV, inst, realm,
+ DEFAULT_TKT_LIFE);
+ if (kret == KSUCCESS)
+ kret = krb_get_cred(NFS_KERBSRV, inst, realm,
+ &kcr);
}
-#endif /* KERBEROS */
+ if (kret == KSUCCESS)
+ kret = krb_mk_req(&ktick.kt, NFS_KERBSRV, inst,
+ realm, 0);
+
+ /*
+ * Fill in the AKN_FULLNAME authenticator and verfier.
+ * Along with the Kerberos ticket, we need to build
+ * the timestamp verifier and encrypt it in CBC mode.
+ */
+ if (kret == KSUCCESS &&
+ ktick.kt.length <= (RPCAUTH_MAXSIZ-3*NFSX_UNSIGNED)
+ && gettimeofday(&ktv, (struct timezone *)0) == 0) {
+ ncd.ncd_authtype = RPCAUTH_KERB4;
+ ncd.ncd_authstr = (u_char *)&ktick;
+ ncd.ncd_authlen = nfsm_rndup(ktick.kt.length) +
+ 3 * NFSX_UNSIGNED;
+ ncd.ncd_verfstr = (u_char *)&kverf;
+ ncd.ncd_verflen = sizeof (kverf);
+ bcopy((caddr_t)kcr.session, (caddr_t)ncd.ncd_key,
+ sizeof (kcr.session));
+ kin.t1 = htonl(ktv.tv_sec);
+ kin.t2 = htonl(ktv.tv_usec);
+ kin.w1 = htonl(NFS_KERBTTL);
+ kin.w2 = htonl(NFS_KERBTTL - 1);
+ bzero((caddr_t)kivec, sizeof (kivec));
+
+ /*
+ * Encrypt kin in CBC mode using the session
+ * key in kcr.
+ */
+ XXX
+
+ /*
+ * Finally, fill the timestamp verifier into the
+ * authenticator and verifier.
+ */
+ ktick.kind = htonl(RPCAKN_FULLNAME);
+ kverf.kind = htonl(RPCAKN_FULLNAME);
+ NFS_KERBW1(ktick.kt) = kout.w1;
+ ktick.kt.length = htonl(ktick.kt.length);
+ kverf.verf.t1 = kout.t1;
+ kverf.verf.t2 = kout.t2;
+ kverf.verf.w2 = kout.w2;
+ nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
+ }
+ setreuid(0, 0);
+#endif /* NFSKERB */
}
}
exit(0);
@@ -440,9 +540,9 @@ getnfsargs(spec, nfsargsp)
#endif
struct timeval pertry, try;
enum clnt_stat clnt_stat;
- int so = RPC_ANYSOCK, i;
+ int so = RPC_ANYSOCK, i, nfsvers, mntvers;
char *hostp, *delimp;
-#ifdef KERBEROS
+#ifdef NFSKERB
char *cp;
#endif
u_short tport;
@@ -507,7 +607,7 @@ getnfsargs(spec, nfsargsp)
warnx("can't get net id for host");
return (0);
}
-#ifdef KERBEROS
+#ifdef NFSKERB
if ((nfsargsp->flags & NFSMNT_KERB)) {
if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
sizeof (u_long), AF_INET)) == (struct hostent *)0) {
@@ -520,33 +620,46 @@ getnfsargs(spec, nfsargsp)
if (cp = strchr(inst, '.'))
*cp = '\0';
}
-#endif /* KERBEROS */
+#endif /* NFSKERB */
+ if (nfsargsp->flags & NFSMNT_NFSV3) {
+ nfsvers = 3;
+ mntvers = 3;
+ } else {
+ nfsvers = 2;
+ mntvers = 1;
+ }
nfhret.stat = EACCES; /* Mark not yet successful */
while (retrycnt > 0) {
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PMAPPORT);
if ((tport = port_no ? port_no :
pmap_getport(&saddr, RPCPROG_NFS,
- NFS_VER2, nfsargsp->sotype == SOCK_STREAM ? IPPROTO_TCP :
- IPPROTO_UDP)) == 0) {
+ nfsvers, nfsproto)) == 0) {
if ((opflags & ISBGRND) == 0)
clnt_pcreateerror("NFS Portmap");
} else {
saddr.sin_port = 0;
pertry.tv_sec = 10;
pertry.tv_usec = 0;
- if ((clp = (nfsargsp->sotype == SOCK_STREAM ?
- clnttcp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
- &so, 0, 0) :
- clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
- pertry, &so))) == NULL) {
+ if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM)
+ clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers,
+ &so, 0, 0);
+ else
+ clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers,
+ pertry, &so);
+ if (clp == NULL) {
if ((opflags & ISBGRND) == 0)
clnt_pcreateerror("Cannot MNT RPC");
} else {
clp->cl_auth = authunix_create_default();
try.tv_sec = 10;
try.tv_usec = 0;
+ if (nfsargsp->flags & NFSMNT_KERB)
+ nfhret.auth = RPCAUTH_KERB4;
+ else
+ nfhret.auth = RPCAUTH_UNIX;
+ nfhret.vers = mntvers;
clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
xdr_dir, spec, xdr_fh, &nfhret, try);
if (clnt_stat != RPC_SUCCESS) {
@@ -596,7 +709,8 @@ getnfsargs(spec, nfsargsp)
nfsargsp->addr = (struct sockaddr *) &saddr;
nfsargsp->addrlen = sizeof (saddr);
}
- nfsargsp->fh = &nfhret.nfh;
+ nfsargsp->fh = nfhret.nfh;
+ nfsargsp->fhsize = nfhret.fhsize;
nfsargsp->hostname = nam;
return (1);
}
@@ -615,22 +729,53 @@ xdr_dir(xdrsp, dirp)
int
xdr_fh(xdrsp, np)
XDR *xdrsp;
- struct nfhret *np;
+ register struct nfhret *np;
{
- if (!xdr_u_long(xdrsp, &(np->stat)))
+ register int i;
+ long auth, authcnt, authfnd = 0;
+
+ if (!xdr_u_long(xdrsp, &np->stat))
return (0);
if (np->stat)
return (1);
- return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
+ switch (np->vers) {
+ case 1:
+ np->fhsize = NFSX_V2FH;
+ return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH));
+ case 3:
+ if (!xdr_long(xdrsp, &np->fhsize))
+ return (0);
+ if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX)
+ return (0);
+ if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
+ return (0);
+ if (!xdr_long(xdrsp, &authcnt))
+ return (0);
+ for (i = 0; i < authcnt; i++) {
+ if (!xdr_long(xdrsp, &auth))
+ return (0);
+ if (auth == np->auth)
+ authfnd++;
+ }
+
+ /*
+ * Some servers, such as DEC's OSF/1 return a nil authenticator
+ * list to indicate RPCAUTH_UNIX.
+ */
+ if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX))
+ np->stat = EAUTH;
+ return (1);
+ };
+ return (0);
}
__dead void
usage()
{
- (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
-"[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
-"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
-"\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
-"\trhost:path node");
+ (void)fprintf(stderr, "\
+usage: mount_nfs [-3KPTUbcdilqs] [-D deadthresh] [-I readdirsize]\n\
+ [-L leaseterm] [-R retrycnt] [-a maxreadahead] [-g maxgroups]\n\
+ [-m realm] [-o options] [-r readsize] [-t timeout] [-w writesize]\n\
+ [-x retrans] rhost:path node\n");
exit(1);
}
diff --git a/sbin/mountd/exports.5 b/sbin/mountd/exports.5
index d32527f71766..fc521f224594 100644
--- a/sbin/mountd/exports.5
+++ b/sbin/mountd/exports.5
@@ -49,7 +49,9 @@ file specifies remote mount points for the
mount protocol per the
.Tn NFS
server specification; see
-.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A" .
+.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A"
+and
+.%T "NFS: Network File System Version 3 Specification, Appendix I" .
.Pp
Each line in the file
(other than comment lines that begin with a #)
@@ -71,7 +73,8 @@ The second is to specify the pathname of the root of the filesystem
followed by the
.Fl alldirs
flag;
-this form allows the host(s) to mount any directory within the filesystem.
+this form allows the host(s) to mount at any point within the filesystem,
+including regular files if the ``-r'' option is used on mountd.
The pathnames must not have any symbolic links in them and should not have
any "." or ".." components.
Mount points for a filesystem may appear on multiple lines each with
@@ -140,8 +143,7 @@ The
.Fl kerb
option specifies that the Kerberos authentication server should be
used to authenticate and map client credentials.
-(Note that this is NOT Sun NFS compatible and
-is supported for TCP transport only.)
+This requires that the kernel be built with the NFSKERB option.
.Pp
The
.Fl ro
diff --git a/sbin/mountd/mountd.8 b/sbin/mountd/mountd.8
index 78f95b51a6a2..7168c1753397 100644
--- a/sbin/mountd/mountd.8
+++ b/sbin/mountd/mountd.8
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)mountd.8 8.1 (Berkeley) 6/9/93
-.\" $Id: mountd.8,v 1.2 1994/09/22 22:16:49 wollman Exp $
+.\" $Id: mountd.8,v 1.3 1995/02/22 21:42:48 ats Exp $
.\"
.Dd September 22, 1994
.Dt MOUNTD 8
@@ -42,7 +42,7 @@
mount requests
.Sh SYNOPSIS
.Nm /sbin/mountd
-.Op Fl n
+.Op Fl nr
.Op Ar exportsfile
.Sh DESCRIPTION
.Xr Mountd
@@ -54,7 +54,9 @@ listens for service requests at the port indicated in the
.Tn NFS
server specification; see
.%T "Network File System Protocol Specification" ,
-RFC1094.
+RFC1094, Appendix A and
+.%T "NFS: Network File System Version 3 Protocol Specification" ,
+Appendix I.
.Pp
Options and operands available for
.Nm mountd :
@@ -65,6 +67,15 @@ The
option allows non-root mount requests to be served.
This should only be specified if there are clients such as PC's,
that require it.
+.It Fl r
+The
+.Fl r
+option allows mount RPCs requests for regular files to be served.
+Although this seems to violate the mount protocol specification, some diskless
+workstations do mount requests for their swapfiles and expect them to be
+regular files. Since a regular file cannot be specified in /etc/exports, the
+entire file system that the swapfiles reside in will have to be exported with
+the ``-alldirs'' flag.
.It Ar exportsfile
The
.Ar exportsfile
diff --git a/sbin/mountd/mountd.c b/sbin/mountd/mountd.c
index 443424466f1b..0887c5938dd8 100644
--- a/sbin/mountd/mountd.c
+++ b/sbin/mountd/mountd.c
@@ -43,7 +43,7 @@ static char copyright[] =
#ifndef lint
/*static char sccsid[] = "From: @(#)mountd.c 8.8 (Berkeley) 2/20/94";*/
static const char rcsid[] =
- "$Id: mountd.c,v 1.7.2.1 1995/06/08 04:34:11 davidg Exp $";
+ "$Id: mountd.c,v 1.8 1995/06/11 19:30:46 rgrimes Exp $";
#endif /*not lint*/
#include <sys/param.h>
@@ -62,7 +62,7 @@ static const char rcsid[] =
#include <netiso/iso.h>
#endif
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <arpa/inet.h>
@@ -100,6 +100,8 @@ struct dirlist {
};
/* dp_flag bits */
#define DP_DEFSET 0x1
+#define DP_HOSTSET 0x2
+#define DP_KERB 0x4
struct exportlist {
struct exportlist *ex_next;
@@ -139,22 +141,29 @@ struct grouplist {
#define GT_IGNORE 0x5
struct hostlist {
+ int ht_flag; /* Uses DP_xx bits */
struct grouplist *ht_grp;
struct hostlist *ht_next;
};
+struct fhreturn {
+ int fhr_flag;
+ int fhr_vers;
+ nfsfh_t fhr_fh;
+};
+
/* Global defs */
char *add_expdir __P((struct dirlist **, char *, int));
void add_dlist __P((struct dirlist **, struct dirlist *,
- struct grouplist *));
+ struct grouplist *, int));
void add_mlist __P((char *, char *));
int check_dirpath __P((char *));
int check_options __P((struct dirlist *));
-int chk_host __P((struct dirlist *, u_long, int *));
+int chk_host __P((struct dirlist *, u_long, int *, int *));
void del_mlist __P((char *, char *));
struct dirlist *dirp_search __P((struct dirlist *, char *));
int do_mount __P((struct exportlist *, struct grouplist *, int,
- struct ucred *, char *, int, struct statfs *));
+ struct ucred *, char *, int, struct statfs *));
int do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
int *, int *, struct ucred *));
struct exportlist *ex_search __P((fsid_t *));
@@ -165,6 +174,7 @@ void free_grp __P((struct grouplist *));
void free_host __P((struct hostlist *));
void get_exportlist __P((void));
int get_host __P((char *, struct grouplist *, struct grouplist *));
+int get_num __P((char *));
struct hostlist *get_ht __P((void));
int get_line __P((void));
void get_mountlist __P((void));
@@ -183,7 +193,7 @@ void send_umntall __P((void));
int umntall_each __P((caddr_t, struct sockaddr_in *));
int xdr_dir __P((XDR *, char *));
int xdr_explist __P((XDR *, caddr_t));
-int xdr_fhs __P((XDR *, nfsv2fh_t *));
+int xdr_fhs __P((XDR *, caddr_t));
int xdr_mlist __P((XDR *, caddr_t));
/* C library */
@@ -205,7 +215,8 @@ struct ucred def_anon = {
1,
{ (gid_t) -2 }
};
-int root_only = 1;
+int resvport_only = 1;
+int dir_only = 1;
int opt_flags;
/* Bits for above */
#define OP_MAPROOT 0x01
@@ -238,6 +249,7 @@ main(argc, argv)
{
SVCXPRT *udptransp, *tcptransp;
int c;
+#ifdef __FreeBSD__
struct vfsconf *vfc;
vfc = getvfsbyname("nfs");
@@ -250,17 +262,21 @@ main(argc, argv)
if(!vfc) {
errx(1, "NFS support is not available in the running kernel");
}
+#endif /* __FreeBSD__ */
- while ((c = getopt(argc, argv, "dn")) != EOF)
+ while ((c = getopt(argc, argv, "dnr")) != EOF)
switch (c) {
+ case 'n':
+ resvport_only = 0;
+ break;
+ case 'r':
+ dir_only = 0;
+ break;
case 'd':
debug = debug ? 0 : 1;
break;
- case 'n':
- root_only = 0;
- break;
default:
- fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
+ fprintf(stderr, "Usage: mountd [-r] [-n] [export_file]\n");
exit(1);
};
argc -= optind;
@@ -300,11 +316,12 @@ main(argc, argv)
syslog(LOG_ERR, "Can't create socket");
exit(1);
}
- pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
- if (!svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
- IPPROTO_UDP) ||
- !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
- IPPROTO_TCP)) {
+ pmap_unset(RPCPROG_MNT, 1);
+ pmap_unset(RPCPROG_MNT, 3);
+ if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) ||
+ !svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) ||
+ !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP) ||
+ !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) {
syslog(LOG_ERR, "Can't register mount");
exit(1);
}
@@ -323,28 +340,21 @@ mntsrv(rqstp, transp)
{
struct exportlist *ep;
struct dirlist *dp;
- nfsv2fh_t nfh;
+ struct fhreturn fhr;
struct authunix_parms *ucr;
struct stat stb;
struct statfs fsb;
struct hostent *hp;
u_long saddr;
+ u_short sport;
char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
- int bad = ENOENT, omask, defset;
- uid_t uid = -2;
-
- /* Get authorization */
- switch (rqstp->rq_cred.oa_flavor) {
- case AUTH_UNIX:
- ucr = (struct authunix_parms *)rqstp->rq_clntcred;
- uid = ucr->aup_uid;
- break;
- case AUTH_NULL:
- default:
- break;
- }
+ int bad = ENOENT, defset, hostset;
+ sigset_t sighup_mask;
+ sigemptyset(&sighup_mask);
+ sigaddset(&sighup_mask, SIGHUP);
saddr = transp->xp_raddr.sin_addr.s_addr;
+ sport = ntohs(transp->xp_raddr.sin_port);
hp = (struct hostent *)NULL;
switch (rqstp->rq_proc) {
case NULLPROC:
@@ -352,7 +362,7 @@ mntsrv(rqstp, transp)
syslog(LOG_ERR, "Can't send reply");
return;
case RPCMNT_MOUNT:
- if ((uid != 0 && root_only) || uid == -2) {
+ if (sport >= IPPORT_RESERVED && resvport_only) {
svcerr_weakauth(transp);
return;
}
@@ -363,11 +373,13 @@ mntsrv(rqstp, transp)
/*
* Get the real pathname and make sure it is a directory
- * that exists.
+ * or a regular file if the -r option was specified
+ * and it exists.
*/
if (realpath(rpcpath, dirpath) == 0 ||
stat(dirpath, &stb) < 0 ||
- (stb.st_mode & S_IFMT) != S_IFDIR ||
+ (!S_ISDIR(stb.st_mode) &&
+ (dir_only || !S_ISREG(stb.st_mode))) ||
statfs(dirpath, &fsb) < 0) {
chdir("/"); /* Just in case realpath doesn't */
if (debug)
@@ -378,26 +390,31 @@ mntsrv(rqstp, transp)
}
/* Check in the exports list */
- omask = sigblock(sigmask(SIGHUP));
+ sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
ep = ex_search(&fsb.f_fsid);
- defset = 0;
- if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
+ hostset = defset = 0;
+ if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
((dp = dirp_search(ep->ex_dirl, dirpath)) &&
- chk_host(dp, saddr, &defset)) ||
+ chk_host(dp, saddr, &defset, &hostset)) ||
(defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
scan_tree(ep->ex_dirl, saddr) == 0))) {
+ if (hostset & DP_HOSTSET)
+ fhr.fhr_flag = hostset;
+ else
+ fhr.fhr_flag = defset;
+ fhr.fhr_vers = rqstp->rq_vers;
/* Get the file handle */
- bzero((caddr_t)&nfh, sizeof(nfh));
- if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
+ bzero((caddr_t)&fhr.fhr_fh, sizeof(nfsfh_t));
+ if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
bad = errno;
syslog(LOG_ERR, "Can't get fh for %s", dirpath);
if (!svc_sendreply(transp, xdr_long,
(caddr_t)&bad))
syslog(LOG_ERR, "Can't send reply");
- sigsetmask(omask);
+ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
return;
}
- if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
+ if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
syslog(LOG_ERR, "Can't send reply");
if (hp == NULL)
hp = gethostbyaddr((caddr_t)&saddr,
@@ -414,14 +431,14 @@ mntsrv(rqstp, transp)
if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
syslog(LOG_ERR, "Can't send reply");
}
- sigsetmask(omask);
+ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
return;
case RPCMNT_DUMP:
if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
syslog(LOG_ERR, "Can't send reply");
return;
case RPCMNT_UMOUNT:
- if ((uid != 0 && root_only) || uid == -2) {
+ if (sport >= IPPORT_RESERVED && resvport_only) {
svcerr_weakauth(transp);
return;
}
@@ -437,7 +454,7 @@ mntsrv(rqstp, transp)
del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
return;
case RPCMNT_UMNTALL:
- if ((uid != 0 && root_only) || uid == -2) {
+ if (sport >= IPPORT_RESERVED && resvport_only) {
svcerr_weakauth(transp);
return;
}
@@ -470,18 +487,37 @@ xdr_dir(xdrsp, dirp)
}
/*
- * Xdr routine to generate fhstatus
+ * Xdr routine to generate file handle reply
*/
int
-xdr_fhs(xdrsp, nfh)
+xdr_fhs(xdrsp, cp)
XDR *xdrsp;
- nfsv2fh_t *nfh;
+ caddr_t cp;
{
- u_long ok = 0;
+ register struct fhreturn *fhrp = (struct fhreturn *)cp;
+ u_long ok = 0, len, auth;
if (!xdr_long(xdrsp, &ok))
return (0);
- return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
+ switch (fhrp->fhr_vers) {
+ case 1:
+ return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
+ case 3:
+ len = NFSX_V3FH;
+ if (!xdr_long(xdrsp, &len))
+ return (0);
+ if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
+ return (0);
+ if (fhrp->fhr_flag & DP_KERB)
+ auth = RPCAUTH_KERB4;
+ else
+ auth = RPCAUTH_UNIX;
+ len = 1;
+ if (!xdr_long(xdrsp, &len))
+ return (0);
+ return (xdr_long(xdrsp, &auth));
+ };
+ return (0);
}
int
@@ -521,9 +557,12 @@ xdr_explist(xdrsp, cp)
{
struct exportlist *ep;
int false = 0;
- int omask, putdef;
+ int putdef;
+ sigset_t sighup_mask;
- omask = sigblock(sigmask(SIGHUP));
+ sigemptyset(&sighup_mask);
+ sigaddset(&sighup_mask, SIGHUP);
+ sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
ep = exphead;
while (ep) {
putdef = 0;
@@ -535,12 +574,12 @@ xdr_explist(xdrsp, cp)
goto errout;
ep = ep->ex_next;
}
- sigsetmask(omask);
+ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
if (!xdr_bool(xdrsp, &false))
return (0);
return (1);
errout:
- sigsetmask(omask);
+ sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
return (0);
}
@@ -660,6 +699,18 @@ get_exportlist()
struct ufs_args ua;
struct iso_args ia;
struct mfs_args ma;
+#ifdef __NetBSD__
+ struct msdosfs_args da;
+ } targs;
+
+ if (!strcmp(fsp->f_fstypename, MOUNT_MFS) ||
+ !strcmp(fsp->f_fstypename, MOUNT_UFS) ||
+ !strcmp(fsp->f_fstypename, MOUNT_MSDOS) ||
+ !strcmp(fsp->f_fstypename, MOUNT_CD9660)) {
+ targs.ua.fspec = NULL;
+ targs.ua.export.ex_flags = MNT_DELEXPORT;
+ if (mount(fsp->f_fstypename, fsp->f_mntonname,
+#else
} targs;
switch (fsp->f_type) {
@@ -670,6 +721,7 @@ get_exportlist()
targs.ua.fspec = NULL;
targs.ua.export.ex_flags = MNT_DELEXPORT;
if (mount(fsp->f_type, fsp->f_mntonname,
+#endif
fsp->f_flags | MNT_UPDATE,
(caddr_t)&targs) < 0)
syslog(LOG_ERR, "Can't delete exports for %s",
@@ -805,6 +857,7 @@ get_exportlist()
if (get_host(hst, grp, tgrp)) {
syslog(LOG_ERR, "Bad netgroup %s", cp);
getexp_err(ep, tgrp);
+ endnetgrent();
goto nextline;
}
} else if (get_host(cp, grp, tgrp)) {
@@ -865,12 +918,12 @@ get_exportlist()
* Success. Update the data structures.
*/
if (has_host) {
- hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
+ hang_dirp(dirhead, tgrp, ep, opt_flags);
grp->gr_next = grphead;
grphead = tgrp;
} else {
hang_dirp(dirhead, (struct grouplist *)NULL, ep,
- (opt_flags & OP_ALLDIRS));
+ opt_flags);
free_grp(grp);
}
dirhead = (struct dirlist *)NULL;
@@ -994,24 +1047,28 @@ add_expdir(dpp, cp, len)
* and update the entry for host.
*/
void
-hang_dirp(dp, grp, ep, alldirs)
+hang_dirp(dp, grp, ep, flags)
struct dirlist *dp;
struct grouplist *grp;
struct exportlist *ep;
- int alldirs;
+ int flags;
{
struct hostlist *hp;
struct dirlist *dp2;
- if (alldirs) {
+ if (flags & OP_ALLDIRS) {
if (ep->ex_defdir)
free((caddr_t)dp);
else
ep->ex_defdir = dp;
- if (grp == (struct grouplist *)NULL)
+ if (grp == (struct grouplist *)NULL) {
ep->ex_defdir->dp_flag |= DP_DEFSET;
- else while (grp) {
+ if (flags & OP_KERB)
+ ep->ex_defdir->dp_flag |= DP_KERB;
+ } else while (grp) {
hp = get_ht();
+ if (flags & OP_KERB)
+ hp->ht_flag |= DP_KERB;
hp->ht_grp = grp;
hp->ht_next = ep->ex_defdir->dp_hosts;
ep->ex_defdir->dp_hosts = hp;
@@ -1024,7 +1081,7 @@ hang_dirp(dp, grp, ep, alldirs)
*/
while (dp) {
dp2 = dp->dp_left;
- add_dlist(&ep->ex_dirl, dp, grp);
+ add_dlist(&ep->ex_dirl, dp, grp, flags);
dp = dp2;
}
}
@@ -1035,10 +1092,11 @@ hang_dirp(dp, grp, ep, alldirs)
* for the new directory or adding the new node.
*/
void
-add_dlist(dpp, newdp, grp)
+add_dlist(dpp, newdp, grp, flags)
struct dirlist **dpp;
struct dirlist *newdp;
struct grouplist *grp;
+ int flags;
{
struct dirlist *dp;
struct hostlist *hp;
@@ -1048,10 +1106,10 @@ add_dlist(dpp, newdp, grp)
if (dp) {
cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
if (cmp > 0) {
- add_dlist(&dp->dp_left, newdp, grp);
+ add_dlist(&dp->dp_left, newdp, grp, flags);
return;
} else if (cmp < 0) {
- add_dlist(&dp->dp_right, newdp, grp);
+ add_dlist(&dp->dp_right, newdp, grp, flags);
return;
} else
free((caddr_t)newdp);
@@ -1067,13 +1125,18 @@ add_dlist(dpp, newdp, grp)
*/
do {
hp = get_ht();
+ if (flags & OP_KERB)
+ hp->ht_flag |= DP_KERB;
hp->ht_grp = grp;
hp->ht_next = dp->dp_hosts;
dp->dp_hosts = hp;
grp = grp->gr_next;
} while (grp);
- } else
+ } else {
dp->dp_flag |= DP_DEFSET;
+ if (flags & OP_KERB)
+ dp->dp_flag |= DP_KERB;
+ }
}
/*
@@ -1102,10 +1165,11 @@ dirp_search(dp, dirpath)
* Scan for a host match in a directory tree.
*/
int
-chk_host(dp, saddr, defsetp)
+chk_host(dp, saddr, defsetp, hostsetp)
struct dirlist *dp;
u_long saddr;
int *defsetp;
+ int *hostsetp;
{
struct hostlist *hp;
struct grouplist *grp;
@@ -1113,7 +1177,7 @@ chk_host(dp, saddr, defsetp)
if (dp) {
if (dp->dp_flag & DP_DEFSET)
- *defsetp = 1;
+ *defsetp = dp->dp_flag;
hp = dp->dp_hosts;
while (hp) {
grp = hp->ht_grp;
@@ -1122,15 +1186,19 @@ chk_host(dp, saddr, defsetp)
addrp = (u_long **)
grp->gr_ptr.gt_hostent->h_addr_list;
while (*addrp) {
- if (**addrp == saddr)
+ if (**addrp == saddr) {
+ *hostsetp = (hp->ht_flag | DP_HOSTSET);
return (1);
+ }
addrp++;
}
break;
case GT_NET:
if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
- grp->gr_ptr.gt_net.nt_net)
+ grp->gr_ptr.gt_net.nt_net) {
+ *hostsetp = (hp->ht_flag | DP_HOSTSET);
return (1);
+ }
break;
};
hp = hp->ht_next;
@@ -1147,12 +1215,12 @@ scan_tree(dp, saddr)
struct dirlist *dp;
u_long saddr;
{
- int defset;
+ int defset, hostset;
if (dp) {
if (scan_tree(dp->dp_left, saddr))
return (1);
- if (chk_host(dp, saddr, &defset))
+ if (chk_host(dp, saddr, &defset, &hostset))
return (1);
if (scan_tree(dp->dp_right, saddr))
return (1);
@@ -1312,7 +1380,7 @@ get_host(cp, grp, tgrp)
if (isdigit(*cp)) {
saddr = inet_addr(cp);
if (saddr == -1) {
- syslog(LOG_ERR, "Inet_addr failed");
+ syslog(LOG_ERR, "Inet_addr failed for %s", cp);
return (1);
}
if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
@@ -1326,7 +1394,7 @@ get_host(cp, grp, tgrp)
aptr[1] = (char *)NULL;
}
} else {
- syslog(LOG_ERR, "Gethostbyname failed");
+ syslog(LOG_ERR, "Gethostbyname failed for %s", cp);
return (1);
}
}
@@ -1424,6 +1492,7 @@ get_ht()
if (hp == (struct hostlist *)NULL)
out_of_mem();
hp->ht_next = (struct hostlist *)NULL;
+ hp->ht_flag = 0;
return (hp);
}
@@ -1494,6 +1563,9 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
struct ufs_args ua;
struct iso_args ia;
struct mfs_args ma;
+#ifdef __NetBSD__
+ struct msdosfs_args da;
+#endif
} args;
u_long net;
@@ -1569,7 +1641,11 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
* Also, needs to know how to export all types of local
* exportable file systems and not just MOUNT_UFS.
*/
+#ifdef __NetBSD__
+ while (mount(fsb->f_fstypename, dirp,
+#else
while (mount(fsb->f_type, dirp,
+#endif
fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
if (cp)
*cp-- = savedc;
@@ -2033,15 +2109,30 @@ check_dirpath(dirp)
while (*cp && ret) {
if (*cp == '/') {
*cp = '\0';
- if (lstat(dirp, &sb) < 0 ||
- (sb.st_mode & S_IFMT) != S_IFDIR)
+ if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
ret = 0;
*cp = '/';
}
cp++;
}
- if (lstat(dirp, &sb) < 0 ||
- (sb.st_mode & S_IFMT) != S_IFDIR)
+ if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
ret = 0;
return (ret);
}
+
+/*
+ * Just translate an ascii string to an integer.
+ */
+int
+get_num(cp)
+ register char *cp;
+{
+ register int res = 0;
+
+ while (*cp) {
+ if (*cp < '0' || *cp > '9')
+ return (-1);
+ res = res * 10 + (*cp++ - '0');
+ }
+ return (res);
+}
diff --git a/sbin/nfsd/nfsd.8 b/sbin/nfsd/nfsd.8
index a54a5643b661..24573d9dd853 100644
--- a/sbin/nfsd/nfsd.8
+++ b/sbin/nfsd/nfsd.8
@@ -98,7 +98,8 @@ listens for service requests at the port indicated in the
.Tn NFS
server specification; see
.%T "Network File System Protocol Specification" ,
-RFC1094.
+RFC1094 and
+.%T "NFS: Network File System Version 3 Protocol Specification" .
.Pp
If
.Nm nfsd
diff --git a/sbin/nfsd/nfsd.c b/sbin/nfsd/nfsd.c
index 9d4d2263d911..8c8731dab791 100644
--- a/sbin/nfsd/nfsd.c
+++ b/sbin/nfsd/nfsd.c
@@ -63,10 +63,10 @@ static char sccsid[] = "@(#)nfsd.c 8.7 (Berkeley) 2/22/94";
#include <netiso/iso.h>
#endif
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
-#ifdef KERBEROS
+#ifdef NFSKERB
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#endif
@@ -94,16 +94,23 @@ struct nfsd_srvargs nsd;
char **Argv = NULL; /* pointer to argument vector */
char *LastArg = NULL; /* end of argv */
-#ifdef KERBEROS
+#ifdef NFSKERB
char lnam[ANAME_SZ];
KTEXT_ST kt;
-AUTH_DAT auth;
+AUTH_DAT kauth;
char inst[INST_SZ];
+struct nfsrpc_fullblock kin, kout;
+struct nfsrpc_fullverf kverf;
+NFSKERBKEY_T kivec;
+struct timeval ktv;
+NFSKERBKEYSCHED_T kerb_keysched;
#endif
void nonfs __P((int));
void reapchild __P((int));
+#ifdef __FreeBSD__
void setproctitle __P((char *));
+#endif
void usage __P((void));
/*
@@ -139,11 +146,13 @@ main(argc, argv, envp)
#ifdef ISO
struct sockaddr_iso isoaddr, isopeer;
#endif
+ struct timeval ktv;
fd_set ready, sockbits;
int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
char *cp, **cpp;
+#ifdef __FreeBSD__
struct vfsconf *vfc;
vfc = getvfsbyname("nfs");
@@ -156,6 +165,7 @@ main(argc, argv, envp)
if(!vfc) {
errx(1, "NFS is not available in the running kernel");
}
+#endif
/* Save start and extent of argv for setproctitle. */
Argv = argv;
@@ -241,10 +251,12 @@ main(argc, argv, envp)
if (reregister) {
if (udpflag &&
- !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT))
+ (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
+ !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
err(1, "can't register with portmap for UDP.");
if (tcpflag &&
- !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT))
+ (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
+ !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
err(1, "can't register with portmap for TCP.");
exit(0);
}
@@ -261,11 +273,17 @@ main(argc, argv, envp)
continue;
}
- setproctitle("nfsd-srv");
+ setproctitle("server");
nfssvc_flag = NFSSVC_NFSD;
nsd.nsd_nfsd = NULL;
-#ifdef KERBEROS
- nsd.nsd_authstr = (char *)kt.dat;
+#ifdef NFSKERB
+ if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF ||
+ sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK)
+ syslog(LOG_ERR, "Yikes NFSKERB structs not packed!");
+ nsd.nsd_authstr = (u_char *)&kt;
+ nsd.nsd_authlen = sizeof (kt);
+ nsd.nsd_verfstr = (u_char *)&kverf;
+ nsd.nsd_verflen = sizeof (kverf);
#endif
while (nfssvc(nfssvc_flag, &nsd) < 0) {
if (errno != ENEEDAUTH) {
@@ -273,14 +291,27 @@ main(argc, argv, envp)
exit(1);
}
nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
-#ifdef KERBEROS
- kt.length = nsd.nsd_authlen;
- kt.mbz = 0;
- (void)strcpy(inst, "*");
- if (krb_rd_req(&kt, "rcmd",
- inst, nsd.nsd_haddr, &auth, "") == RD_AP_OK &&
- krb_kntoln(&auth, lnam) == KSUCCESS &&
- (pwd = getpwnam(lnam)) != NULL) {
+#ifdef NFSKERB
+ /*
+ * Get the Kerberos ticket out of the authenticator
+ * verify it and convert the principal name to a user
+ * name. The user name is then converted to a set of
+ * user credentials via the password and group file.
+ * Finally, decrypt the timestamp and validate it.
+ * For more info see the IETF Draft "Authentication
+ * in ONC RPC".
+ */
+ kt.length = ntohl(kt.length);
+ if (gettimeofday(&ktv, (struct timezone *)0) == 0 &&
+ kt.length > 0 && kt.length <=
+ (RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) {
+ kin.w1 = NFS_KERBW1(kt);
+ kt.mbz = 0;
+ (void)strcpy(inst, "*");
+ if (krb_rd_req(&kt, NFS_KERBSRV,
+ inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK &&
+ krb_kntoln(&kauth, lnam) == KSUCCESS &&
+ (pwd = getpwnam(lnam)) != NULL) {
cr = &nsd.nsd_cr;
cr->cr_uid = pwd->pw_uid;
cr->cr_groups[0] = pwd->pw_gid;
@@ -301,9 +332,34 @@ main(argc, argv, envp)
break;
}
endgrent();
- nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
+
+ /*
+ * Get the timestamp verifier out of the
+ * authenticator and verifier strings.
+ */
+ kin.t1 = kverf.t1;
+ kin.t2 = kverf.t2;
+ kin.w2 = kverf.w2;
+ bzero((caddr_t)kivec, sizeof (kivec));
+ bcopy((caddr_t)kauth.session,
+ (caddr_t)nsd.nsd_key,sizeof(kauth.session));
+
+ /*
+ * Decrypt the timestamp verifier in CBC mode.
+ */
+ XXX
+
+ /*
+ * Validate the timestamp verifier, to
+ * check that the session key is ok.
+ */
+ nsd.nsd_timestamp.tv_sec = ntohl(kout.t1);
+ nsd.nsd_timestamp.tv_usec = ntohl(kout.t2);
+ nsd.nsd_ttl = ntohl(kout.w1);
+ if ((nsd.nsd_ttl - 1) == ntohl(kout.w2))
+ nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
}
-#endif /* KERBEROS */
+#endif /* NFSKERB */
}
exit(0);
}
@@ -323,7 +379,8 @@ main(argc, argv, envp)
syslog(LOG_ERR, "can't bind udp addr");
exit(1);
}
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
+ if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
+ !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
syslog(LOG_ERR, "can't register with udp portmap");
exit(1);
}
@@ -403,7 +460,8 @@ main(argc, argv, envp)
syslog(LOG_ERR, "listen failed");
exit(1);
}
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
+ !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
syslog(LOG_ERR, "can't register tcp with portmap");
exit(1);
}
@@ -492,7 +550,7 @@ main(argc, argv, envp)
if (connect_type_cnt == 0)
exit(0);
- setproctitle("nfsd-master");
+ setproctitle("master");
/*
* Loop forever accepting connections and passing the sockets
@@ -566,7 +624,7 @@ main(argc, argv, envp)
void
usage()
{
- (void)fprintf(stderr, "nfsd %s\n", USAGE);
+ (void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
exit(1);
}
@@ -582,9 +640,10 @@ reapchild(signo)
int signo;
{
- while (wait3(NULL, WNOHANG, NULL));
+ while (wait3(NULL, WNOHANG, NULL) > 0);
}
+#ifdef __FreeBSD__
void
setproctitle(a)
char *a;
@@ -593,9 +652,10 @@ setproctitle(a)
char buf[80];
cp = Argv[0];
- (void)snprintf(buf, sizeof(buf), "%s", a);
+ (void)snprintf(buf, sizeof(buf), "nfsd-%s", a);
(void)strncpy(cp, buf, LastArg - cp);
cp += strlen(cp);
while (cp < LastArg)
*cp++ = '\0';
}
+#endif /* __FreeBSD__ */
diff --git a/sbin/nfsiod/nfsiod.c b/sbin/nfsiod/nfsiod.c
index d066329ab4d9..0a6985fad4dd 100644
--- a/sbin/nfsiod/nfsiod.c
+++ b/sbin/nfsiod/nfsiod.c
@@ -50,8 +50,10 @@ static char sccsid[] = "@(#)nfsiod.c 8.3 (Berkeley) 2/22/94";
#include <sys/ucred.h>
#include <sys/wait.h>
#include <sys/mount.h>
+#include <sys/time.h>
-#include <nfs/nfsv2.h>
+#include <nfs/rpcv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <err.h>
diff --git a/sys/nfs/nfs.h b/sys/nfs/nfs.h
index cbf80c6d7fd6..e1a0f07a71ef 100644
--- a/sys/nfs/nfs.h
+++ b/sys/nfs/nfs.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs.h 8.1 (Berkeley) 6/10/93
- * $Id: nfs.h,v 1.8 1994/11/02 00:11:00 wollman Exp $
+ * $Id: nfs.h,v 1.9 1995/02/14 06:22:18 phk Exp $
*/
#ifndef _NFS_NFS_H_
@@ -45,11 +45,12 @@
*/
#define NFS_MAXIOVEC 34
-#define NFS_HZ 25 /* Ticks per second for NFS timeouts */
-#define NFS_TIMEO (1*NFS_HZ) /* Default timeout = 1 second */
-#define NFS_MINTIMEO (1*NFS_HZ) /* Min timeout to use */
-#define NFS_MAXTIMEO (60*NFS_HZ) /* Max timeout to backoff to */
-#define NFS_MINIDEMTIMEO (5*NFS_HZ) /* Min timeout for non-idempotent ops*/
+#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */
+#define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */
+#define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */
+#define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */
+#define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */
+#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/
#define NFS_MAXREXMIT 100 /* Stop counting after this many */
#define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */
#define NFS_RETRANS 10 /* Num of retrans for soft mounts */
@@ -62,13 +63,81 @@
#endif
#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */
#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */
+#define NFS_READDIRSIZE 8192 /* Def. readdir size */
#define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */
#define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */
-#define NFS_MAXREADDIR NFS_MAXDATA /* Max. size of directory read */
#define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */
-#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */
-#define NFS_DIRBLKSIZ 1024 /* Size of an NFS directory block */
+#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */
+#define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */
+#ifndef NFS_GATHERDELAY
+#define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */
+#endif
+#define NFS_DIRBLKSIZ 4096 /* Must be a multiple of DIRBLKSIZ */
+
+/*
+ * Oddballs
+ */
#define NMOD(a) ((a) % nfs_asyncdaemons)
+#define NFS_CMPFH(n, f, s) \
+ ((n)->n_fhsize == (s) && !bcmp((caddr_t)(n)->n_fhp, (caddr_t)(f), (s)))
+#define NFS_ISV3(v) (VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV3)
+#define NFS_SRVMAXDATA(n) \
+ (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \
+ NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA)
+
+/*
+ * XXX
+ * sys/buf.h should be editted to change B_APPENDWRITE --> B_NEEDCOMMIT, but
+ * until then...
+ * Same goes for sys/malloc.h, which needs M_NFSDIROFF,
+ * M_NFSRVDESC and M_NFSBIGFH added.
+ * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an
+ * exclusive create.
+ * The B_INVAFTERWRITE flag should be set to whatever is required by the
+ * buffer cache code to say "Invalidate the block after it is written back".
+ */
+#ifndef B_NEEDCOMMIT
+#define B_NEEDCOMMIT B_APPENDWRITE
+#endif
+#ifndef M_NFSRVDESC
+#define M_NFSRVDESC M_TEMP
+#endif
+#ifndef M_NFSDIROFF
+#define M_NFSDIROFF M_TEMP
+#endif
+#ifndef M_NFSBIGFH
+#define M_NFSBIGFH M_TEMP
+#endif
+#ifndef VA_EXCLUSIVE
+#define VA_EXCLUSIVE 0
+#endif
+#ifdef __FreeBSD__
+#define B_INVAFTERWRITE B_NOCACHE
+#else
+#define B_INVAFTERWRITE B_INVAL
+#endif
+
+/*
+ * These ifdefs try to handle the differences between the various 4.4BSD-Lite
+ * based vfs interfaces.
+ * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to
+ * differentiate between NetBSD-1.0 and NetBSD-current, so..
+ * I also don't know about BSDi's 2.0 release.
+ */
+#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+#define HAS_VOPLEASE 1
+#endif
+#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+#define HAS_VOPREVOKE 1
+#endif
+
+/*
+ * The IO_METASYNC flag should be implemented for local file systems.
+ * (Until then, it is nothin at all.)
+ */
+#ifndef IO_METASYNC
+#define IO_METASYNC 0
+#endif
/*
* Set the attribute timeout based on how recently the file has been modified.
@@ -80,6 +149,20 @@
(time.tv_sec - (np)->n_mtime) / 10))
/*
+ * Expected allocation sizes for major data structures. If the actual size
+ * of the structure exceeds these sizes, then malloc() will be allocating
+ * almost twice the memory required. This is used in nfs_init() to warn
+ * the sysadmin that the size of a structure should be reduced.
+ * (These sizes are always a power of 2. If the kernel malloc() changes
+ * to one that does not allocate space in powers of 2 size, then this all
+ * becomes bunk!)
+ */
+#define NFS_NODEALLOC 256
+#define NFS_MNTALLOC 512
+#define NFS_SVCALLOC 256
+#define NFS_UIDALLOC 128
+
+/*
* Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs
* should ever try and use it.
*/
@@ -95,7 +178,12 @@ struct nfsd_srvargs {
u_long nsd_haddr; /* Ip address of client */
struct ucred nsd_cr; /* Cred. uid maps to */
int nsd_authlen; /* Length of auth string (ret) */
- char *nsd_authstr; /* Auth string (ret) */
+ u_char *nsd_authstr; /* Auth string (ret) */
+ int nsd_verflen; /* and the verfier */
+ u_char *nsd_verfstr;
+ struct timeval nsd_timestamp; /* timestamp from verifier */
+ u_long nsd_ttl; /* credential ttl (sec) */
+ NFSKERBKEY_T nsd_key; /* Session key */
};
struct nfsd_cargs {
@@ -103,7 +191,10 @@ struct nfsd_cargs {
uid_t ncd_authuid; /* Effective uid */
int ncd_authtype; /* Type of authenticator */
int ncd_authlen; /* Length of authenticator string */
- char *ncd_authstr; /* Authenticator string */
+ u_char *ncd_authstr; /* Authenticator string */
+ int ncd_verflen; /* and the verifier */
+ u_char *ncd_verfstr;
+ NFSKERBKEY_T ncd_key; /* Session key */
};
/*
@@ -142,6 +233,7 @@ struct nfsstats {
int srvnqnfs_leases;
int srvnqnfs_maxleases;
int srvnqnfs_getleases;
+ int srvvop_writes;
};
/*
@@ -173,7 +265,7 @@ struct nfsstats {
* such as SIGALRM will not expect file I/O system calls to be interrupted
* by them and break.
*/
-#ifdef KERNEL
+#if defined(KERNEL) || defined(_KERNEL)
struct uio; struct buf; struct vattr; struct nameidata; /* XXX */
@@ -224,17 +316,29 @@ TAILQ_HEAD(, nfsreq) nfs_reqq;
#define R_MUSTRESEND 0x40 /* Must resend request */
#define R_GETONEREP 0x80 /* Probe for one reply only */
-extern struct nfsstats nfsstats;
-
/*
* A list of nfssvc_sock structures is maintained with all the sockets
* that require service by the nfsd.
* The nfsuid structs hang off of the nfssvc_sock structs in both lru
* and uid hash lists.
*/
-#define NUIDHASHSIZ 32
+#ifndef NFS_UIDHASHSIZ
+#define NFS_UIDHASHSIZ 29 /* Tune the size of nfssvc_sock with this */
+#endif
#define NUIDHASH(sock, uid) \
- (&(sock)->ns_uidhashtbl[(uid) & (sock)->ns_uidhash])
+ (&(sock)->ns_uidhashtbl[(uid) % NFS_UIDHASHSIZ])
+#ifndef NFS_WDELAYHASHSIZ
+#define NFS_WDELAYHASHSIZ 16 /* and with this */
+#endif
+#define NWDELAYHASH(sock, f) \
+ (&(sock)->ns_wdelayhashtbl[(*((u_long *)(f))) % NFS_WDELAYHASHSIZ])
+#ifndef NFS_MUIDHASHSIZ
+#define NFS_MUIDHASHSIZ 67 /* Tune the size of nfsmount with this */
+#endif
+#define NMUIDHASH(nmp, uid) \
+ (&(nmp)->nm_uidhashtbl[(uid) % NFS_MUIDHASHSIZ])
+#define NFSNOHASH(fhsum) \
+ (&nfsnodehashtbl[(fhsum) & nfsnodehash])
/*
* Network address hash list element
@@ -248,35 +352,41 @@ struct nfsuid {
TAILQ_ENTRY(nfsuid) nu_lru; /* LRU chain */
LIST_ENTRY(nfsuid) nu_hash; /* Hash list */
int nu_flag; /* Flags */
- uid_t nu_uid; /* Uid mapped by this entry */
union nethostaddr nu_haddr; /* Host addr. for dgram sockets */
struct ucred nu_cr; /* Cred uid mapped to */
+ int nu_expire; /* Expiry time (sec) */
+ struct timeval nu_timestamp; /* Kerb. timestamp */
+ u_long nu_nickname; /* Nickname on server */
+ NFSKERBKEY_T nu_key; /* and session key */
};
#define nu_inetaddr nu_haddr.had_inetaddr
#define nu_nam nu_haddr.had_nam
/* Bits for nu_flag */
#define NU_INETADDR 0x1
+#define NU_NAM 0x2
+#define NU_NETFAM(u) (((u)->nu_flag & NU_INETADDR) ? AF_INET : AF_ISO)
struct nfssvc_sock {
TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */
TAILQ_HEAD(, nfsuid) ns_uidlruhead;
- LIST_HEAD(, nfsuid) *ns_uidhashtbl;
- u_long ns_uidhash;
-
- int ns_flag;
- u_long ns_sref;
struct file *ns_fp;
struct socket *ns_so;
- int ns_solock;
struct mbuf *ns_nam;
- int ns_cc;
struct mbuf *ns_raw;
struct mbuf *ns_rawend;
- int ns_reclen;
struct mbuf *ns_rec;
struct mbuf *ns_recend;
+ struct mbuf *ns_frag;
+ int ns_flag;
+ int ns_solock;
+ int ns_cc;
+ int ns_reclen;
int ns_numuids;
+ u_long ns_sref;
+ LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */
+ LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ];
+ LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ];
};
/* Bits for "ns_flag" */
@@ -285,6 +395,7 @@ struct nfssvc_sock {
#define SLP_NEEDQ 0x04
#define SLP_DISCONN 0x08
#define SLP_GETSTREAM 0x10
+#define SLP_LASTFRAG 0x20
#define SLP_ALLFLAGS 0xff
TAILQ_HEAD(, nfssvc_sock) nfssvc_sockhead;
@@ -296,73 +407,124 @@ int nfssvc_sockhead_flag;
* One of these structures is allocated for each nfsd.
*/
struct nfsd {
- TAILQ_ENTRY(nfsd) nd_chain; /* List of all nfsd's */
- int nd_flag; /* NFSD_ flags */
- struct nfssvc_sock *nd_slp; /* Current socket */
- struct mbuf *nd_nam; /* Client addr for datagram req. */
- struct mbuf *nd_mrep; /* Req. mbuf list */
- struct mbuf *nd_md;
- caddr_t nd_dpos; /* Position in list */
- int nd_procnum; /* RPC procedure number */
- u_long nd_retxid; /* RPC xid */
- int nd_repstat; /* Reply status value */
- struct ucred nd_cr; /* Credentials for req. */
- int nd_nqlflag; /* Leasing flag */
- u_long nd_duration; /* Lease duration */
- int nd_authlen; /* Authenticator len */
- u_char nd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */
- struct proc *nd_procp; /* Proc ptr */
+ TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */
+ int nfsd_flag; /* NFSD_ flags */
+ struct nfssvc_sock *nfsd_slp; /* Current socket */
+ int nfsd_authlen; /* Authenticator len */
+ u_char nfsd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */
+ int nfsd_verflen; /* and the Verifier */
+ u_char nfsd_verfstr[RPCVERF_MAXSIZ];
+ struct proc *nfsd_procp; /* Proc ptr */
+ struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */
};
-/* Bits for "nd_flag" */
+/* Bits for "nfsd_flag" */
#define NFSD_WAITING 0x01
#define NFSD_REQINPROG 0x02
#define NFSD_NEEDAUTH 0x04
#define NFSD_AUTHFAIL 0x08
+/*
+ * This structure is used by the server for describing each request.
+ * Some fields are used only when write request gathering is performed.
+ */
+struct nfsrv_descript {
+ u_quad_t nd_time; /* Write deadline (usec) */
+ off_t nd_off; /* Start byte offset */
+ off_t nd_eoff; /* and end byte offset */
+ LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */
+ LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */
+ LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */
+ struct mbuf *nd_mrep; /* Request mbuf list */
+ struct mbuf *nd_md; /* Current dissect mbuf */
+ struct mbuf *nd_mreq; /* Reply mbuf list */
+ struct mbuf *nd_nam; /* and socket addr */
+ struct mbuf *nd_nam2; /* return socket addr */
+ caddr_t nd_dpos; /* Current dissect pos */
+ int nd_procnum; /* RPC # */
+ int nd_stable; /* storage type */
+ int nd_flag; /* nd_flag */
+ int nd_len; /* Length of this write */
+ int nd_repstat; /* Reply status */
+ u_long nd_retxid; /* Reply xid */
+ u_long nd_duration; /* Lease duration */
+ struct timeval nd_starttime; /* Time RPC initiated */
+ fhandle_t nd_fh; /* File handle */
+ struct ucred nd_cr; /* Credentials */
+};
+
+/* Bits for "nd_flag" */
+#define ND_READ LEASE_READ
+#define ND_WRITE LEASE_WRITE
+#define ND_CHECK 0x04
+#define ND_LEASE (ND_READ | ND_WRITE | ND_CHECK)
+#define ND_NFSV3 0x08
+#define ND_NQNFS 0x10
+#define ND_KERBNICK 0x20
+#define ND_KERBFULL 0x40
+#define ND_KERBAUTH (ND_KERBNICK | ND_KERBFULL)
+
TAILQ_HEAD(, nfsd) nfsd_head;
int nfsd_head_flag;
#define NFSD_CHECKSLP 0x01
+/*
+ * These macros compare nfsrv_descript structures.
+ */
+#define NFSW_CONTIG(o, n) \
+ ((o)->nd_eoff >= (n)->nd_off && \
+ !bcmp((caddr_t)&(o)->nd_fh, (caddr_t)&(n)->nd_fh, NFSX_V3FH))
+
+#define NFSW_SAMECRED(o, n) \
+ (((o)->nd_flag & ND_KERBAUTH) == ((n)->nd_flag & ND_KERBAUTH) && \
+ !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \
+ sizeof (struct ucred)))
+
int nfs_reply __P((struct nfsreq *));
-int nfs_getreq __P((struct nfsd *,int));
+int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int));
int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *));
-int nfs_rephead __P((int,struct nfsd *,int,int,u_quad_t *,struct mbuf **,struct mbuf **,caddr_t *));
+int nfs_rephead __P((int,struct nfsrv_descript *,struct nfssvc_sock *,int,int,u_quad_t *,struct mbuf **,struct mbuf **,caddr_t *));
int nfs_sndlock __P((int *,struct nfsreq *));
int nfs_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *));
int nfs_vinvalbuf __P((struct vnode *,int,struct ucred *,struct proc *,int));
int nfs_readrpc __P((struct vnode *,struct uio *,struct ucred *));
-int nfs_writerpc __P((struct vnode *,struct uio *,struct ucred *,int));
+int nfs_writerpc __P((struct vnode *,struct uio *,struct ucred *,int *,int *));
int nfs_readdirrpc __P((register struct vnode *,struct uio *,struct ucred *));
+int nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct proc *));
int nfs_asyncio __P((struct buf *,struct ucred *));
int nfs_doio __P((struct buf *,struct ucred *,struct proc *));
int nfs_readlinkrpc __P((struct vnode *,struct uio *,struct ucred *));
int nfs_sigintr __P((struct nfsmount *,struct nfsreq *r,struct proc *));
-int nfs_readdirlookrpc __P((struct vnode *,register struct uio *,struct ucred *));
+int nfs_readdirplusrpc __P((struct vnode *,register struct uio *,struct ucred *));
int nfsm_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *));
-int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **,struct ucred *,struct nfssvc_sock *,struct mbuf *,int *));
+void nfsm_srvfattr __P((struct nfsrv_descript *,struct vattr *,struct nfs_fattr *));
+void nfsm_srvwcc __P((struct nfsrv_descript *,int,struct vattr *,int,struct vattr *,struct mbuf **,char **));
+void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct mbuf **,char **));
+int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **,struct ucred *,struct nfssvc_sock *,struct mbuf *,int *,int));
int nfsrv_access __P((struct vnode *,int,struct ucred *,int,struct proc *));
int netaddr_match __P((int,union nethostaddr *,struct mbuf *));
int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *));
int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *));
-int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct proc *));
+int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int));
void nfsm_adj __P((struct mbuf *,int,int));
int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *));
void nfsrv_initcache __P((void));
int nfs_rcvlock __P((struct nfsreq *));
-int nfs_getauth __P((struct nfsmount *,struct nfsreq *,struct ucred *,int *,char **,int *));
+int nfs_getauth __P((struct nfsmount *,struct nfsreq *,struct ucred *,char **,int *,char *,int *,NFSKERBKEY_T));
+int nfs_getnickauth __P((struct nfsmount *,struct ucred *,char **,int *,char *,int));
+int nfs_savenickauth __P((struct nfsmount *,struct ucred *,int,NFSKERBKEY_T,struct mbuf **,char **,struct mbuf *));
int nfs_msg __P((struct proc *,char *,char *));
int nfs_adv __P((struct mbuf **,caddr_t *,int,int));
int nfsrv_getstream __P((struct nfssvc_sock *,int));
void nfs_nhinit __P((void));
void nfs_timer __P((void*));
-struct nfsnodehashhead * nfs_hash __P((nfsv2fh_t *));
+u_long nfs_hash __P((nfsfh_t *,int));
int nfssvc_iod __P((struct proc *));
int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *));
int nfssvc_addsock __P((struct file *,struct mbuf *));
-int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *));
-int nfsrv_getcache __P((struct mbuf *,struct nfsd *,struct mbuf **));
-void nfsrv_updatecache __P((struct mbuf *,struct nfsd *,int,struct mbuf *));
+int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **));
+int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **));
+void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *));
int mountnfs __P((struct nfs_args *,struct mount *,struct mbuf *,char *,char *,struct vnode **));
int nfs_connect __P((struct nfsmount *,struct nfsreq *));
int nfs_getattrcache __P((struct vnode *,struct vattr *));
@@ -370,9 +532,20 @@ int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long));
int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *));
int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *));
void nfsrv_init __P((int));
+void nfs_clearcommit __P((struct mount *));
+int nfsrv_errmap __P((struct nfsrv_descript *, int));
+void nfsrvw_coalesce __P((struct nfsrv_descript *,struct nfsrv_descript *));
+void nfsrvw_sort __P((gid_t [],int));
+void nfsrv_setcred __P((struct ucred *,struct ucred *));
+int nfs_flush __P((struct vnode *,struct ucred *,int,struct proc *,int));
+int nfs_writebp __P((struct buf *,int));
int nfsrv_vput __P(( struct vnode * ));
int nfsrv_vrele __P(( struct vnode * ));
int nfsrv_vmio __P(( struct vnode * ));
+int nfsrv_writegather __P((struct nfsrv_descript **, struct nfssvc_sock *,
+ struct proc *, struct mbuf **));
+int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *,
+ struct proc *p));
#endif /* KERNEL */
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c
index f92901262000..f9ae8b6fd00f 100644
--- a/sys/nfs/nfs_bio.c
+++ b/sys/nfs/nfs_bio.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94
- * $Id: nfs_bio.c,v 1.13 1995/05/21 21:39:21 davidg Exp $
+ * $Id: nfs_bio.c,v 1.14 1995/05/30 08:12:35 rgrimes Exp $
*/
#include <sys/param.h>
@@ -49,16 +49,30 @@
#include <vm/vm.h>
-#include <nfs/nfsnode.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsmount.h>
#include <nfs/nqnfs.h>
+#include <nfs/nfsnode.h>
struct buf *nfs_getcacheblk();
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern int nfs_numasync;
+extern struct nfsstats nfsstats;
+
+/*
+ * Ifdefs for FreeBSD-current's merged VM/buffer cache. It is unfortunate
+ * that this isn't done inside getblk() and brelse() so these calls
+ * wouldn't need to be here.
+ */
+#ifdef B_VMIO
+#define vnode_pager_uncache(vp)
+#else
+#define vfs_busy_pages(bp, f)
+#define vfs_unbusy_pages(bp)
+#define vfs_dirty_pages(bp)
+#endif
/*
* Vnode op for read using bio
@@ -72,29 +86,28 @@ nfs_bioread(vp, uio, ioflag, cred)
struct ucred *cred;
{
register struct nfsnode *np = VTONFS(vp);
- register int biosize, diff;
+ register int biosize, diff, i;
struct buf *bp = 0, *rabp;
struct vattr vattr;
struct proc *p;
- struct nfsmount *nmp;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
daddr_t lbn, rabn;
int bufsize;
int nra, error = 0, n = 0, on = 0, not_readin;
+ nfsquad_t tquad;
-#ifdef lint
- ioflag = ioflag;
-#endif /* lint */
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ)
panic("nfs_read mode");
#endif
if (uio->uio_resid == 0)
return (0);
- if (uio->uio_offset < 0 && vp->v_type != VDIR)
+ if (uio->uio_offset < 0)
return (EINVAL);
- nmp = VFSTONFS(vp->v_mount);
- biosize = NFS_MAXDGRAMDATA;
p = uio->uio_procp;
+ if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
+ (void)nfs_fsinfo(nmp, vp, cred, p);
+ biosize = nmp->nm_rsize;
/*
* For nfs, cache consistency can only be maintained approximately.
* Although RFC1094 does not specify the criteria, the following is
@@ -107,8 +120,6 @@ nfs_bioread(vp, uio, ioflag, cred)
* server, so flush all of the file's data out of the cache.
* Then force a getattr rpc to ensure that you have up to date
* attributes.
- * The mount flag NFSMNT_MYWRITE says "Assume that my writes are
- * the ones changing the modify time.
* NB: This implies that cache data can be read when up to
* NFS_ATTRTIMEO seconds out of date. If you find that you need current
* attributes this could be forced by setting n_attrstamp to 0 before
@@ -116,14 +127,15 @@ nfs_bioread(vp, uio, ioflag, cred)
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 && vp->v_type != VLNK) {
if (np->n_flag & NMODIFIED) {
- if ((nmp->nm_flag & NFSMNT_MYWRITE) == 0 ||
- vp->v_type != VREG) {
+ if (vp->v_type != VREG) {
+ if (vp->v_type != VDIR)
+ panic("nfs: bioread, not dir");
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
}
np->n_attrstamp = 0;
- np->n_direofoffset = 0;
error = VOP_GETATTR(vp, &vattr, cred, p);
if (error)
return (error);
@@ -133,7 +145,8 @@ nfs_bioread(vp, uio, ioflag, cred)
if (error)
return (error);
if (np->n_mtime != vattr.va_mtime.ts_sec) {
- np->n_direofoffset = 0;
+ if (vp->v_type == VDIR)
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@@ -147,27 +160,24 @@ nfs_bioread(vp, uio, ioflag, cred)
* Get a valid lease. If cached data is stale, flush it.
*/
if (nmp->nm_flag & NFSMNT_NQNFS) {
- if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
+ if (NQNFS_CKINVALID(vp, np, ND_READ)) {
do {
- error = nqnfs_getlease(vp, NQL_READ, cred, p);
+ error = nqnfs_getlease(vp, ND_READ, cred, p);
} while (error == NQNFS_EXPIRED);
if (error)
return (error);
if (np->n_lrev != np->n_brev ||
(np->n_flag & NQNFSNONCACHE) ||
((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
- if (vp->v_type == VDIR) {
- np->n_direofoffset = 0;
- cache_purge(vp);
- }
+ if (vp->v_type == VDIR)
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
np->n_brev = np->n_lrev;
}
} else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) {
- np->n_direofoffset = 0;
- cache_purge(vp);
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@@ -176,33 +186,27 @@ nfs_bioread(vp, uio, ioflag, cred)
if (np->n_flag & NQNFSNONCACHE) {
switch (vp->v_type) {
case VREG:
- error = nfs_readrpc(vp, uio, cred);
- break;
+ return (nfs_readrpc(vp, uio, cred));
case VLNK:
- error = nfs_readlinkrpc(vp, uio, cred);
- break;
+ return (nfs_readlinkrpc(vp, uio, cred));
case VDIR:
- error = nfs_readdirrpc(vp, uio, cred);
break;
default:
printf(" NQNFSNONCACHE: type %x unexpected\n",
vp->v_type);
- break;
};
- return (error);
}
switch (vp->v_type) {
case VREG:
nfsstats.biocache_reads++;
lbn = uio->uio_offset / biosize;
- on = uio->uio_offset & (biosize-1);
+ on = uio->uio_offset & (biosize - 1);
not_readin = 1;
/*
* Start the read ahead(s), as required.
*/
- if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
- lbn == vp->v_lastr + 1) {
+ if (nfs_numasync > 0 && nmp->nm_readahead > 0) {
for (nra = 0; nra < nmp->nm_readahead &&
(lbn + 1 + nra) * biosize < np->n_size; nra++) {
rabn = lbn + 1 + nra;
@@ -296,32 +300,55 @@ again:
break;
case VDIR:
nfsstats.biocache_readdirs++;
- lbn = (daddr_t)uio->uio_offset;
+ lbn = uio->uio_offset / NFS_DIRBLKSIZ;
+ on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, p);
if (!bp)
- return (EINTR);
-
+ return (EINTR);
if ((bp->b_flags & B_CACHE) == 0) {
- bp->b_flags |= B_READ;
- vfs_busy_pages(bp, 0);
- error = nfs_doio(bp, cred, p);
- if (error) {
- bp->b_flags |= B_ERROR;
- brelse(bp);
- return (error);
+ bp->b_flags |= B_READ;
+ vfs_busy_pages(bp, 0);
+ error = nfs_doio(bp, cred, p);
+ if (error) {
+ brelse(bp);
+ while (error == NFSERR_BAD_COOKIE) {
+ nfs_invaldir(vp);
+ error = nfs_vinvalbuf(vp, 0, cred, p, 1);
+ /*
+ * Yuck! The directory has been modified on the
+ * server. The only way to get the block is by
+ * reading from the beginning to get all the
+ * offset cookies.
+ */
+ for (i = 0; i <= lbn && !error; i++) {
+ bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, p);
+ if (!bp)
+ return (EINTR);
+ if ((bp->b_flags & B_DONE) == 0) {
+ bp->b_flags |= B_READ;
+ vfs_busy_pages(bp, 0);
+ error = nfs_doio(bp, cred, p);
+ if (error)
+ brelse(bp);
+ }
+ }
}
+ if (error)
+ return (error);
+ }
}
/*
* If not eof and read aheads are enabled, start one.
* (You need the current block first, so that you have the
- * directory offset cookie of the next block.
+ * directory offset cookie of the next block.)
*/
- rabn = bp->b_blkno;
if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
- rabn != 0 && rabn != np->n_direofoffset &&
- !incore(vp, rabn)) {
- rabp = nfs_getcacheblk(vp, rabn, NFS_DIRBLKSIZ, p);
+ (np->n_direofoffset == 0 ||
+ (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) &&
+ !(np->n_flag & NQNFSNONCACHE) &&
+ !incore(vp, lbn + 1)) {
+ rabp = nfs_getcacheblk(vp, lbn + 1, NFS_DIRBLKSIZ, p);
if (rabp) {
if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
rabp->b_flags |= (B_READ | B_ASYNC);
@@ -336,11 +363,10 @@ again:
}
}
}
- on = 0;
- n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid);
+ n = min(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on);
break;
default:
- printf(" nfsbioread: type %x unexpected\n",vp->v_type);
+ printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
break;
};
@@ -354,11 +380,11 @@ again:
n = 0;
break;
case VDIR:
- uio->uio_offset = bp->b_blkno;
+ if (np->n_flag & NQNFSNONCACHE)
+ bp->b_flags |= B_INVAL;
break;
default:
- printf(" nfsbioread: type %x unexpected\n",vp->v_type);
- break;
+ printf(" nfs_bioread: type %x unexpected\n",vp->v_type);
}
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n > 0);
@@ -386,10 +412,10 @@ nfs_write(ap)
int ioflag = ap->a_ioflag;
struct buf *bp;
struct vattr vattr;
- struct nfsmount *nmp;
- daddr_t lbn;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ daddr_t lbn, bn;
int bufsize;
- int n, on, error = 0;
+ int n, on, error = 0, iomode, must_commit;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_WRITE)
@@ -403,6 +429,8 @@ nfs_write(ap)
np->n_flag &= ~NWRITEERR;
return (np->n_error);
}
+ if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
+ (void)nfs_fsinfo(nmp, vp, cred, p);
if (ioflag & (IO_APPEND | IO_SYNC)) {
if (np->n_flag & NMODIFIED) {
np->n_attrstamp = 0;
@@ -418,7 +446,6 @@ nfs_write(ap)
uio->uio_offset = np->n_size;
}
}
- nmp = VFSTONFS(vp->v_mount);
if (uio->uio_offset < 0)
return (EINVAL);
if (uio->uio_resid == 0)
@@ -437,7 +464,7 @@ nfs_write(ap)
* will be the same size within a filesystem. nfs_writerpc will
* still use nm_wsize when sizing the rpc's.
*/
- biosize = NFS_MAXDGRAMDATA;
+ biosize = nmp->nm_rsize;
do {
/*
@@ -445,12 +472,11 @@ nfs_write(ap)
*/
/*
* Check for a valid write lease.
- * If non-cachable, just do the rpc
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKINVALID(vp, np, NQL_WRITE)) {
+ NQNFS_CKINVALID(vp, np, ND_WRITE)) {
do {
- error = nqnfs_getlease(vp, NQL_WRITE, cred, p);
+ error = nqnfs_getlease(vp, ND_WRITE, cred, p);
} while (error == NQNFS_EXPIRED);
if (error)
return (error);
@@ -462,8 +488,13 @@ nfs_write(ap)
np->n_brev = np->n_lrev;
}
}
- if (np->n_flag & NQNFSNONCACHE)
- return (nfs_writerpc(vp, uio, cred, ioflag));
+ if ((np->n_flag & NQNFSNONCACHE) && uio->uio_iovcnt == 1) {
+ iomode = NFSV3WRITE_FILESYNC;
+ error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit);
+ if (must_commit)
+ nfs_clearcommit(vp->v_mount);
+ return (error);
+ }
nfsstats.biocache_writes++;
lbn = uio->uio_offset / biosize;
on = uio->uio_offset & (biosize-1);
@@ -509,9 +540,9 @@ again:
* In case getblk() and/or bwrite() delayed us.
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKINVALID(vp, np, NQL_WRITE)) {
+ NQNFS_CKINVALID(vp, np, ND_WRITE)) {
do {
- error = nqnfs_getlease(vp, NQL_WRITE, cred, p);
+ error = nqnfs_getlease(vp, ND_WRITE, cred, p);
} while (error == NQNFS_EXPIRED);
if (error) {
brelse(bp);
@@ -540,7 +571,6 @@ again:
bp->b_dirtyoff = on;
bp->b_dirtyend = on + n;
}
-#ifndef notdef
if (bp->b_validend == 0 || bp->b_validend < bp->b_dirtyoff ||
bp->b_validoff > bp->b_dirtyend) {
bp->b_validoff = bp->b_dirtyoff;
@@ -549,13 +579,6 @@ again:
bp->b_validoff = min(bp->b_validoff, bp->b_dirtyoff);
bp->b_validend = max(bp->b_validend, bp->b_dirtyend);
}
-#else
- bp->b_validoff = bp->b_dirtyoff;
- bp->b_validend = bp->b_dirtyend;
-#endif
- if (ioflag & IO_APPEND)
- bp->b_flags |= B_APPENDWRITE;
-
/*
* If the lease is non-cachable or IO_SYNC do bwrite().
*/
@@ -564,10 +587,16 @@ again:
error = VOP_BWRITE(bp);
if (error)
return (error);
+ if (np->n_flag & NQNFSNONCACHE) {
+ error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error)
+ return (error);
+ }
} else if ((n + on) == biosize &&
(nmp->nm_flag & NFSMNT_NQNFS) == 0) {
bp->b_proc = (struct proc *)0;
- bawrite(bp);
+ bp->b_flags |= B_ASYNC;
+ (void)nfs_writebp(bp, 0);
} else
bdwrite(bp);
} while (uio->uio_resid > 0 && n > 0);
@@ -590,6 +619,7 @@ nfs_getcacheblk(vp, bn, size, p)
{
register struct buf *bp;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ int biosize = nmp->nm_rsize;
if (nmp->nm_flag & NFSMNT_INT) {
bp = getblk(vp, bn, size, PCATCH, 0);
@@ -602,7 +632,7 @@ nfs_getcacheblk(vp, bn, size, p)
bp = getblk(vp, bn, size, 0, 0);
if( vp->v_type == VREG)
- bp->b_blkno = (bn * NFS_MAXDGRAMDATA) / DEV_BSIZE;
+ bp->b_blkno = (bn * biosize) / DEV_BSIZE;
return (bp);
}
@@ -689,6 +719,7 @@ nfs_asyncio(bp, cred)
bp->b_rcred = cred;
}
} else {
+ bp->b_flags |= B_WRITEINPROG;
if (bp->b_wcred == NOCRED && cred != NOCRED) {
crhold(cred);
bp->b_wcred = cred;
@@ -700,7 +731,25 @@ nfs_asyncio(bp, cred)
wakeup((caddr_t)&nfs_iodwant[i]);
return (0);
}
- return (EIO);
+
+ /*
+ * If it is a read or a write already marked B_WRITEINPROG or B_NOCACHE
+ * return EIO so the process will call nfs_doio() and do it
+ * synchronously.
+ */
+ if (bp->b_flags & (B_READ | B_WRITEINPROG | B_NOCACHE))
+ return (EIO);
+
+ /*
+ * Just turn the async write into a delayed write, instead of
+ * doing in synchronously. Hopefully, at least one of the nfsiods
+ * is currently doing a write for this file and will pick up the
+ * delayed writes before going back to sleep.
+ */
+ bp->b_flags |= B_DELWRI;
+ reassignbuf(bp, bp->b_vp);
+ biodone(bp);
+ return (0);
}
/*
@@ -717,9 +766,10 @@ nfs_doio(bp, cr, p)
register struct vnode *vp;
struct nfsnode *np;
struct nfsmount *nmp;
- int error = 0, diff, len;
+ int error = 0, diff, len, iomode, must_commit = 0;
struct uio uio;
struct iovec io;
+ nfsquad_t tquad;
vp = bp->b_vp;
np = VTONFS(vp);
@@ -740,15 +790,18 @@ nfs_doio(bp, cr, p)
io.iov_len = uiop->uio_resid = bp->b_bcount;
/* mapping was done by vmapbuf() */
io.iov_base = bp->b_data;
- uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
if (bp->b_flags & B_READ) {
uiop->uio_rw = UIO_READ;
nfsstats.read_physios++;
error = nfs_readrpc(vp, uiop, cr);
} else {
+ int com;
+
+ iomode = NFSV3WRITE_DATASYNC;
uiop->uio_rw = UIO_WRITE;
nfsstats.write_physios++;
- error = nfs_writerpc(vp, uiop, cr,0);
+ error = nfs_writerpc(vp, uiop, cr, &iomode, &com);
}
if (error) {
bp->b_flags |= B_ERROR;
@@ -760,7 +813,7 @@ nfs_doio(bp, cr, p)
uiop->uio_rw = UIO_READ;
switch (vp->v_type) {
case VREG:
- uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
nfsstats.read_bios++;
error = nfs_readrpc(vp, uiop, cr);
if (!error) {
@@ -773,7 +826,7 @@ nfs_doio(bp, cr, p)
* Just zero fill the rest of the valid area.
*/
diff = bp->b_bcount - uiop->uio_resid;
- len = np->n_size - (bp->b_blkno * DEV_BSIZE
+ len = np->n_size - (((u_quad_t)bp->b_blkno) * DEV_BSIZE
+ diff);
if (len > 0) {
len = min(len, uiop->uio_resid);
@@ -786,31 +839,34 @@ nfs_doio(bp, cr, p)
}
if (p && (vp->v_flag & VTEXT) &&
(((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKINVALID(vp, np, NQL_READ) &&
+ NQNFS_CKINVALID(vp, np, ND_READ) &&
np->n_lrev != np->n_brev) ||
(!(nmp->nm_flag & NFSMNT_NQNFS) &&
np->n_mtime != np->n_vattr.va_mtime.ts_sec))) {
uprintf("Process killed due to text file modification\n");
psignal(p, SIGKILL);
+#ifdef __NetBSD__
+ p->p_holdcnt++;
+#else
p->p_flag |= P_NOSWAP;
+#endif
}
break;
case VLNK:
- uiop->uio_offset = 0;
+ uiop->uio_offset = (off_t)0;
nfsstats.readlink_bios++;
error = nfs_readlinkrpc(vp, uiop, cr);
break;
case VDIR:
- uiop->uio_offset = bp->b_lblkno;
nfsstats.readdir_bios++;
- if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS)
- error = nfs_readdirlookrpc(vp, uiop, cr);
- else
- error = nfs_readdirrpc(vp, uiop, cr);
- /*
- * Save offset cookie in b_blkno.
- */
- bp->b_blkno = uiop->uio_offset;
+ uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
+ if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
+ error = nfs_readdirplusrpc(vp, uiop, cr);
+ if (error == NFSERR_NOTSUPP)
+ nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
+ }
+ if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
+ error = nfs_readdirrpc(vp, uiop, cr);
break;
default:
printf("nfs_doio: type %x unexpected\n",vp->v_type);
@@ -821,32 +877,44 @@ nfs_doio(bp, cr, p)
bp->b_error = error;
}
} else {
-
if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
if (bp->b_dirtyend > bp->b_dirtyoff) {
io.iov_len = uiop->uio_resid = bp->b_dirtyend
- - bp->b_dirtyoff;
- uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
- + bp->b_dirtyoff;
+ - bp->b_dirtyoff;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE
+ + bp->b_dirtyoff;
io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
uiop->uio_rw = UIO_WRITE;
nfsstats.write_bios++;
- if (bp->b_flags & B_APPENDWRITE)
- error = nfs_writerpc(vp, uiop, cr, IO_APPEND);
+ if ((bp->b_flags & (B_ASYNC | B_NEEDCOMMIT | B_NOCACHE)) == B_ASYNC)
+ iomode = NFSV3WRITE_UNSTABLE;
+ else
+ iomode = NFSV3WRITE_FILESYNC;
+ bp->b_flags |= B_WRITEINPROG;
+ error = nfs_writerpc(vp, uiop, cr, &iomode, &must_commit);
+ if (!error && iomode == NFSV3WRITE_UNSTABLE)
+ bp->b_flags |= B_NEEDCOMMIT;
else
- error = nfs_writerpc(vp, uiop, cr, 0);
- bp->b_flags &= ~(B_WRITEINPROG | B_APPENDWRITE);
+ bp->b_flags &= ~B_NEEDCOMMIT;
+ bp->b_flags &= ~B_WRITEINPROG;
- /*
- * For an interrupted write, the buffer is still valid and the
- * write hasn't been pushed to the server yet, so we can't set
- * B_ERROR and report the interruption by setting B_EINTR. For
- * the B_ASYNC case, B_EINTR is not relevant, so the rpc attempt
- * is essentially a noop.
- */
- if (error == EINTR) {
+ /*
+ * For an interrupted write, the buffer is still valid
+ * and the write hasn't been pushed to the server yet,
+ * so we can't set B_ERROR and report the interruption
+ * by setting B_EINTR. For the B_ASYNC case, B_EINTR
+ * is not relevant, so the rpc attempt is essentially
+ * a noop. For the case of a V3 write rpc not being
+ * committed to stable storage, the block is still
+ * dirty and requires either a commit rpc or another
+ * write rpc with iomode == NFSV3WRITE_FILESYNC before
+ * the block is reused. This is indicated by setting
+ * the B_DELWRI and B_NEEDCOMMIT flags.
+ */
+ if (error == EINTR
+ || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
bp->b_flags &= ~(B_INVAL|B_NOCACHE);
bp->b_flags |= B_DELWRI;
@@ -874,6 +942,8 @@ nfs_doio(bp, cr, p)
}
}
bp->b_resid = uiop->uio_resid;
+ if (must_commit)
+ nfs_clearcommit(vp->v_mount);
biodone(bp);
return (error);
}
diff --git a/sys/nfs/nfs_common.c b/sys/nfs/nfs_common.c
index 1653c8b4cb3d..350ba469d289 100644
--- a/sys/nfs/nfs_common.c
+++ b/sys/nfs/nfs_common.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94
- * $Id: nfs_subs.c,v 1.15 1995/05/30 08:12:43 rgrimes Exp $
+ * $Id: nfs_subs.c,v 1.16 1995/06/14 06:23:38 joerg Exp $
*/
/*
@@ -52,6 +52,7 @@
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/malloc.h>
#ifdef VFS_LKM
#include <sys/sysent.h>
#include <sys/syscall.h>
@@ -60,7 +61,7 @@
#include <vm/vm.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfsnode.h>
#include <nfs/nfs.h>
#include <nfs/xdr_subs.h>
@@ -78,31 +79,455 @@
#include <netiso/iso.h>
#endif
-#define TRUE 1
-#define FALSE 0
-
/*
* Data items converted to xdr at startup, since they are constant
* This is kinda hokey, but may save a little time doing byte swaps
*/
-u_long nfs_procids[NFS_NPROCS];
u_long nfs_xdrneg1;
u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
- rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
+ rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
rpc_auth_kerb;
-u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
+u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
/* And other global data */
static u_long nfs_xid = 0;
-enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
+enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
+enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
+int nfs_ticks;
+
+/*
+ * Mapping of old NFS Version 2 RPC numbers to generic numbers.
+ */
+int nfsv3_procid[NFS_NPROCS] = {
+ NFSPROC_NULL,
+ NFSPROC_GETATTR,
+ NFSPROC_SETATTR,
+ NFSPROC_NOOP,
+ NFSPROC_LOOKUP,
+ NFSPROC_READLINK,
+ NFSPROC_READ,
+ NFSPROC_NOOP,
+ NFSPROC_WRITE,
+ NFSPROC_CREATE,
+ NFSPROC_REMOVE,
+ NFSPROC_RENAME,
+ NFSPROC_LINK,
+ NFSPROC_SYMLINK,
+ NFSPROC_MKDIR,
+ NFSPROC_RMDIR,
+ NFSPROC_READDIR,
+ NFSPROC_FSSTAT,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP
+};
+
+/*
+ * and the reverse mapping from generic to Version 2 procedure numbers
+ */
+int nfsv2_procid[NFS_NPROCS] = {
+ NFSV2PROC_NULL,
+ NFSV2PROC_GETATTR,
+ NFSV2PROC_SETATTR,
+ NFSV2PROC_LOOKUP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_READLINK,
+ NFSV2PROC_READ,
+ NFSV2PROC_WRITE,
+ NFSV2PROC_CREATE,
+ NFSV2PROC_MKDIR,
+ NFSV2PROC_SYMLINK,
+ NFSV2PROC_CREATE,
+ NFSV2PROC_REMOVE,
+ NFSV2PROC_RMDIR,
+ NFSV2PROC_RENAME,
+ NFSV2PROC_LINK,
+ NFSV2PROC_READDIR,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_STATFS,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+};
+
+/*
+ * Maps errno values to nfs error numbers.
+ * Use NFSERR_IO as the catch all for ones not specifically defined in
+ * RFC 1094.
+ */
+static u_char nfsrv_v2errmap[ELAST] = {
+ NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
+ NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
+ NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO,
+};
+
+/*
+ * Maps errno values to nfs error numbers.
+ * Although it is not obvious whether or not NFS clients really care if
+ * a returned error value is in the specified list for the procedure, the
+ * safest thing to do is filter them appropriately. For Version 2, the
+ * X/Open XNFS document is the only specification that defines error values
+ * for each RPC (The RFC simply lists all possible error values for all RPCs),
+ * so I have decided to not do this for Version 2.
+ * The first entry is the default error return and the rest are the valid
+ * errors for that RPC in increasing numeric order.
+ */
+static short nfsv3err_null[] = {
+ 0,
+ 0,
+};
+
+static short nfsv3err_getattr[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_setattr[] = {
+ NFSERR_IO,
+ NFSERR_PERM,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOT_SYNC,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_lookup[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_NAMETOL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_access[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_readlink[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_read[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_NXIO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_write[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_FBIG,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_create[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_mkdir[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_symlink[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_mknod[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ NFSERR_BADTYPE,
+ 0,
+};
+
+static short nfsv3err_remove[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_rmdir[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_INVAL,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_NOTEMPTY,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_rename[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_XDEV,
+ NFSERR_NOTDIR,
+ NFSERR_ISDIR,
+ NFSERR_INVAL,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_MLINK,
+ NFSERR_NAMETOL,
+ NFSERR_NOTEMPTY,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_link[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_XDEV,
+ NFSERR_NOTDIR,
+ NFSERR_INVAL,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_MLINK,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_readdir[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_BAD_COOKIE,
+ NFSERR_TOOSMALL,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_readdirplus[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_BAD_COOKIE,
+ NFSERR_NOTSUPP,
+ NFSERR_TOOSMALL,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_fsstat[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_fsinfo[] = {
+ NFSERR_STALE,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_pathconf[] = {
+ NFSERR_STALE,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_commit[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short *nfsrv_v3errmap[] = {
+ nfsv3err_null,
+ nfsv3err_getattr,
+ nfsv3err_setattr,
+ nfsv3err_lookup,
+ nfsv3err_access,
+ nfsv3err_readlink,
+ nfsv3err_read,
+ nfsv3err_write,
+ nfsv3err_create,
+ nfsv3err_mkdir,
+ nfsv3err_symlink,
+ nfsv3err_mknod,
+ nfsv3err_remove,
+ nfsv3err_rmdir,
+ nfsv3err_rename,
+ nfsv3err_link,
+ nfsv3err_readdir,
+ nfsv3err_readdirplus,
+ nfsv3err_fsstat,
+ nfsv3err_fsinfo,
+ nfsv3err_pathconf,
+ nfsv3err_commit,
+};
+
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
-extern int nqnfs_piggy[NFS_NPROCS];
extern struct nfsrtt nfsrtt;
extern time_t nqnfsstarttime;
-extern u_long nqnfs_prog, nqnfs_vers;
extern int nqsrv_clockskew;
extern int nqsrv_writeslack;
extern int nqsrv_maxlease;
+extern struct nfsstats nfsstats;
+extern int nqnfs_piggy[NFS_NPROCS];
+extern nfstype nfsv2_type[9];
+extern nfstype nfsv3_type[9];
+extern struct nfsnodehashhead *nfsnodehashtbl;
+extern u_long nfsnodehash;
#ifdef VFS_LKM
struct getfh_args;
@@ -167,14 +592,16 @@ nfsm_reqh(vp, procid, hsiz, bposp)
* Returns the head of the mbuf list.
*/
struct mbuf *
-nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
- mrest_len, mbp, xidp)
+nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
+ verf_str, mrest, mrest_len, mbp, xidp)
register struct ucred *cr;
- int nqnfs;
+ int nmflag;
int procid;
int auth_type;
int auth_len;
char *auth_str;
+ int verf_len;
+ char *verf_str;
struct mbuf *mrest;
int mrest_len;
struct mbuf **mbp;
@@ -188,15 +615,13 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
int siz, grpsiz, authsiz;
authsiz = nfsm_rndup(auth_len);
- if (auth_type == RPCAUTH_NQNFS)
- authsiz += 2 * NFSX_UNSIGNED;
MGETHDR(mb, M_WAIT, MT_DATA);
- if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
+ if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
MCLGET(mb, M_WAIT);
- } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
- MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
+ } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
+ MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
} else {
- MH_ALIGN(mb, 8*NFSX_UNSIGNED);
+ MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
}
mb->m_len = 0;
mreq = mb;
@@ -205,20 +630,26 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
/*
* First the RPC header.
*/
- nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
+ nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
if (++nfs_xid == 0)
nfs_xid++;
*tl++ = *xidp = txdr_unsigned(nfs_xid);
*tl++ = rpc_call;
*tl++ = rpc_vers;
- if (nqnfs) {
+ if (nmflag & NFSMNT_NQNFS) {
*tl++ = txdr_unsigned(NQNFS_PROG);
- *tl++ = txdr_unsigned(NQNFS_VER1);
+ *tl++ = txdr_unsigned(NQNFS_VER3);
} else {
*tl++ = txdr_unsigned(NFS_PROG);
- *tl++ = txdr_unsigned(NFS_VER2);
+ if (nmflag & NFSMNT_NFSV3)
+ *tl++ = txdr_unsigned(NFS_VER3);
+ else
+ *tl++ = txdr_unsigned(NFS_VER2);
}
- *tl++ = txdr_unsigned(procid);
+ if (nmflag & NFSMNT_NFSV3)
+ *tl++ = txdr_unsigned(procid);
+ else
+ *tl++ = txdr_unsigned(nfsv2_procid[procid]);
/*
* And then the authorization cred.
@@ -237,10 +668,7 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
for (i = 1; i <= grpsiz; i++)
*tl++ = txdr_unsigned(cr->cr_groups[i]);
break;
- case RPCAUTH_NQNFS:
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(cr->cr_uid);
- *tl = txdr_unsigned(auth_len);
+ case RPCAUTH_KERB4:
siz = auth_len;
while (siz > 0) {
if (M_TRAILINGSPACE(mb) == 0) {
@@ -266,11 +694,43 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
}
break;
};
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(RPCAUTH_NULL);
- *tl = 0;
+
+ /*
+ * And the verifier...
+ */
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ if (verf_str) {
+ *tl++ = txdr_unsigned(RPCAUTH_KERB4);
+ *tl = txdr_unsigned(verf_len);
+ siz = verf_len;
+ while (siz > 0) {
+ if (M_TRAILINGSPACE(mb) == 0) {
+ MGET(mb2, M_WAIT, MT_DATA);
+ if (siz >= MINCLSIZE)
+ MCLGET(mb2, M_WAIT);
+ mb->m_next = mb2;
+ mb = mb2;
+ mb->m_len = 0;
+ bpos = mtod(mb, caddr_t);
+ }
+ i = min(siz, M_TRAILINGSPACE(mb));
+ bcopy(verf_str, bpos, i);
+ mb->m_len += i;
+ verf_str += i;
+ bpos += i;
+ siz -= i;
+ }
+ if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
+ for (i = 0; i < siz; i++)
+ *bpos++ = '\0';
+ mb->m_len += siz;
+ }
+ } else {
+ *tl++ = txdr_unsigned(RPCAUTH_NULL);
+ *tl = 0;
+ }
mb->m_next = mrest;
- mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
+ mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
mreq->m_pkthdr.rcvif = (struct ifnet *)0;
*mbp = mb;
return (mreq);
@@ -603,6 +1063,25 @@ nfs_init()
{
register int i;
+ /*
+ * Check to see if major data structures haven't bloated.
+ */
+ if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
+ printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
+ printf("Try reducing NFS_SMALLFH\n");
+ }
+ if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
+ printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
+ printf("Try reducing NFS_MUIDHASHSIZ\n");
+ }
+ if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
+ printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
+ printf("Try reducing NFS_UIDHASHSIZ\n");
+ }
+ if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
+ printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
+ printf("Try unionizing the nu_nickname and nu_flag fields\n");
+ }
nfsrtt.pos = 0;
rpc_vers = txdr_unsigned(RPC_VER2);
rpc_call = txdr_unsigned(RPC_CALL);
@@ -611,17 +1090,16 @@ nfs_init()
rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
rpc_autherr = txdr_unsigned(RPC_AUTHERR);
- rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
- rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
- nfs_vers = txdr_unsigned(NFS_VER2);
+ rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
nfs_prog = txdr_unsigned(NFS_PROG);
+ nqnfs_prog = txdr_unsigned(NQNFS_PROG);
nfs_true = txdr_unsigned(TRUE);
nfs_false = txdr_unsigned(FALSE);
nfs_xdrneg1 = txdr_unsigned(-1);
- /* Loop thru nfs procids */
- for (i = 0; i < NFS_NPROCS; i++)
- nfs_procids[i] = txdr_unsigned(i);
+ nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
+ if (nfs_ticks < 1)
+ nfs_ticks = 1;
/* Ensure async daemons disabled */
for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
nfs_iodwant[i] = (struct proc *)0;
@@ -637,8 +1115,6 @@ nfs_init()
nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
+ nqsrv_clockskew + nqsrv_writeslack;
NQLOADNOVRAM(nqnfsstarttime);
- nqnfs_prog = txdr_unsigned(NQNFS_PROG);
- nqnfs_vers = txdr_unsigned(NQNFS_VER1);
CIRCLEQ_INIT(&nqtimerhead);
nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
}
@@ -649,6 +1125,7 @@ nfs_init()
TAILQ_INIT(&nfs_reqq);
nfs_timer(0);
+#ifdef __FreeBSD__
/*
* Set up lease_check and lease_updatetime so that other parts
* of the system can call us, if we are loadable.
@@ -662,6 +1139,7 @@ nfs_init()
sysent[SYS_getfh].sy_narg = 2;
sysent[SYS_getfh].sy_call = getfh;
#endif
+#endif
return (0);
}
@@ -689,57 +1167,65 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
{
register struct vnode *vp = *vpp;
register struct vattr *vap;
- register struct nfsv2_fattr *fp;
+ register struct nfs_fattr *fp;
register struct nfsnode *np;
register struct nfsnodehashhead *nhpp;
register long t1;
- caddr_t dpos, cp2;
- int error = 0, isnq;
+ caddr_t cp2;
+ int error = 0, rdev;
struct mbuf *md;
enum vtype vtyp;
u_short vmode;
- long rdev;
struct timespec mtime;
struct vnode *nvp;
+ quad_t tval;
+ int v3 = NFS_ISV3(vp);
md = *mdp;
- dpos = *dposp;
- t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
- isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
- error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
- if (error)
+ t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
+ if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
return (error);
- fp = (struct nfsv2_fattr *)cp2;
- vtyp = nfstov_type(fp->fa_type);
- vmode = fxdr_unsigned(u_short, fp->fa_mode);
- /*
- * XXX
- *
- * The duplicate information returned in fa_type and fa_mode
- * is an ambiguity in the NFS version 2 protocol.
- *
- * VREG should be taken literally as a regular file. If a
- * server intents to return some type information differently
- * in the upper bits of the mode field (e.g. for sockets, or
- * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
- * leave the examination of the mode bits even in the VREG
- * case to avoid breakage for bogus servers, but we make sure
- * that there are actually type bits set in the upper part of
- * fa_mode (and failing that, trust the va_type field).
- *
- * NFSv3 cleared the issue, and requires fa_mode to not
- * contain any type information (while also introduing sockets
- * and FIFOs for fa_type).
- */
- if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
- vtyp = IFTOVT(vmode);
- if (isnq) {
- rdev = fxdr_unsigned(long, fp->fa_nqrdev);
- fxdr_nqtime(&fp->fa_nqmtime, &mtime);
+ fp = (struct nfs_fattr *)cp2;
+ if (v3) {
+ vtyp = nfsv3tov_type(fp->fa_type);
+ vmode = fxdr_unsigned(u_short, fp->fa_mode);
+ rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
+ fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
+ fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
} else {
- rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
- fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
+ vtyp = nfsv2tov_type(fp->fa_type);
+ vmode = fxdr_unsigned(u_short, fp->fa_mode);
+ /*
+ * XXX
+ *
+ * The duplicate information returned in fa_type and fa_mode
+ * is an ambiguity in the NFS version 2 protocol.
+ *
+ * VREG should be taken literally as a regular file. If a
+ * server intents to return some type information differently
+ * in the upper bits of the mode field (e.g. for sockets, or
+ * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
+ * leave the examination of the mode bits even in the VREG
+ * case to avoid breakage for bogus servers, but we make sure
+ * that there are actually type bits set in the upper part of
+ * fa_mode (and failing that, trust the va_type field).
+ *
+ * NFSv3 cleared the issue, and requires fa_mode to not
+ * contain any type information (while also introduing sockets
+ * and FIFOs for fa_type).
+ */
+ if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
+ vtyp = IFTOVT(vmode);
+ rdev = fxdr_unsigned(long, fp->fa2_rdev);
+ fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
+
+ /*
+ * Really ugly NFSv2 kludge.
+ */
+ if (vtyp == VCHR && rdev == 0xffffffff)
+ vtyp = VFIFO;
}
+
/*
* If v_type == VNON it is a new node, so fill in the v_type,
* n_mtime fields. Check to see if it represents a special
@@ -749,10 +1235,15 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
*/
np = VTONFS(vp);
if (vp->v_type == VNON) {
- if (vtyp == VCHR && rdev == 0xffffffff)
- vp->v_type = vtyp = VFIFO;
- else
- vp->v_type = vtyp;
+ /*
+ * If we had a lock and it turns out that the vnode
+ * is an object which we don't want to lock (e.g. VDIR)
+ * to avoid nasty hanging problems on a server crash,
+ * then release it here.
+ */
+ if (vtyp != VREG && VOP_ISLOCKED(vp))
+ VOP_UNLOCK(vp);
+ vp->v_type = vtyp;
if (vp->v_type == VFIFO) {
vp->v_op = fifo_nfsv2nodeop_p;
}
@@ -773,7 +1264,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
* Reinitialize aliased node.
*/
np->n_vnode = nvp;
- nhpp = nfs_hash(&np->n_fh);
+ nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize));
LIST_INSERT_HEAD(nhpp, np, n_hash);
*vpp = vp = nvp;
}
@@ -783,31 +1274,34 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
vap = &np->n_vattr;
vap->va_type = vtyp;
vap->va_mode = (vmode & 07777);
- vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
- vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
- vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
vap->va_rdev = (dev_t)rdev;
vap->va_mtime = mtime;
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
- if (isnq) {
- fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
- vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
- fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
- vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
- fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
- vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
- fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
- vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
- fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
+ if (v3) {
+ vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
+ vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
+ vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
+ fxdr_hyper(&fp->fa3_size, &vap->va_size);
+ vap->va_blocksize = NFS_FABLKSIZE;
+ fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
+ vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
+ fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
+ fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
+ vap->va_flags = 0;
+ vap->va_filerev = 0;
} else {
- vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
- vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
- vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
- vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
- fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
+ vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
+ vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
+ vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
+ vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
+ vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
+ vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
+ vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
+ fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
vap->va_flags = 0;
- fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
- vap->va_gen = 0;
+ vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
+ vap->va_ctime.ts_nsec = 0;
+ vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
vap->va_filerev = 0;
}
if (vap->va_size != np->n_size) {
@@ -824,26 +1318,13 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
np->n_size = vap->va_size;
}
np->n_attrstamp = time.tv_sec;
- *dposp = dpos;
- *mdp = md;
if (vaper != NULL) {
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
-#ifdef notdef
- if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
- if (np->n_size > vap->va_size)
- vaper->va_size = np->n_size;
-#endif
if (np->n_flag & NCHG) {
- if (np->n_flag & NACC) {
- vaper->va_atime.ts_sec = np->n_atim.tv_sec;
- vaper->va_atime.ts_nsec =
- np->n_atim.tv_usec * 1000;
- }
- if (np->n_flag & NUPD) {
- vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
- vaper->va_mtime.ts_nsec =
- np->n_mtim.tv_usec * 1000;
- }
+ if (np->n_flag & NACC)
+ vaper->va_atime = np->n_atim;
+ if (np->n_flag & NUPD)
+ vaper->va_mtime = np->n_mtim;
}
}
return (0);
@@ -862,12 +1343,7 @@ nfs_getattrcache(vp, vaper)
register struct nfsnode *np = VTONFS(vp);
register struct vattr *vap;
- if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
- if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
- nfsstats.attrcache_misses++;
- return (ENOENT);
- }
- } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
+ if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
nfsstats.attrcache_misses++;
return (ENOENT);
}
@@ -887,23 +1363,11 @@ nfs_getattrcache(vp, vaper)
np->n_size = vap->va_size;
}
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
-#ifdef notdef
- if ((np->n_flag & NMODIFIED) == 0) {
- np->n_size = vaper->va_size;
- vnode_pager_setsize(vp, (u_long)np->n_size);
- } else if (np->n_size > vaper->va_size)
- if (np->n_size > vaper->va_size)
- vaper->va_size = np->n_size;
-#endif
if (np->n_flag & NCHG) {
- if (np->n_flag & NACC) {
- vaper->va_atime.ts_sec = np->n_atim.tv_sec;
- vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
- }
- if (np->n_flag & NUPD) {
- vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
- vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
- }
+ if (np->n_flag & NACC)
+ vaper->va_atime = np->n_atim;
+ if (np->n_flag & NUPD)
+ vaper->va_mtime = np->n_mtim;
}
return (0);
}
@@ -912,7 +1376,7 @@ nfs_getattrcache(vp, vaper)
* Set up nameidata for a lookup() call and do it
*/
int
-nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
+nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
register struct nameidata *ndp;
fhandle_t *fhp;
int len;
@@ -920,7 +1384,9 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
struct mbuf *nam;
struct mbuf **mdp;
caddr_t *dposp;
+ struct vnode **retdirp;
struct proc *p;
+ int kerbflag;
{
register int i, rem;
register struct mbuf *md;
@@ -929,6 +1395,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
int error, rdonly;
struct componentname *cnp = &ndp->ni_cnd;
+ *retdirp = (struct vnode *)0;
MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
/*
* Copy the name from the mbuf list to ndp->ni_pnbuf
@@ -950,7 +1417,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
rem = md->m_len;
}
if (*fromcp == '\0' || *fromcp == '/') {
- error = EINVAL;
+ error = EACCES;
goto out;
}
cnp->cn_hash += (unsigned char)*fromcp;
@@ -964,26 +1431,24 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
if (len > 0) {
if (rem >= len)
*dposp += len;
- else {
- error = nfs_adv(mdp, dposp, len, rem);
- if (error)
- goto out;
- }
+ else if (error = nfs_adv(mdp, dposp, len, rem))
+ goto out;
}
ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
cnp->cn_nameptr = cnp->cn_pnbuf;
/*
* Extract and set starting directory.
*/
- error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
- nam, &rdonly);
- if (error)
+ if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
+ nam, &rdonly, kerbflag))
goto out;
if (dp->v_type != VDIR) {
nfsrv_vrele(dp);
error = ENOTDIR;
goto out;
}
+ VREF(dp);
+ *retdirp = dp;
ndp->ni_startdir = dp;
if (rdonly)
cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
@@ -993,8 +1458,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
* And call lookup() to do the real work
*/
cnp->cn_proc = p;
- error = lookup(ndp);
- if (error)
+ if (error = lookup(ndp))
goto out;
/*
* Check for encountering a symbolic link
@@ -1087,6 +1551,109 @@ nfsm_adj(mp, len, nul)
}
/*
+ * Make these functions instead of macros, so that the kernel text size
+ * doesn't get too big...
+ */
+void
+nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
+ struct nfsrv_descript *nfsd;
+ int before_ret;
+ register struct vattr *before_vap;
+ int after_ret;
+ struct vattr *after_vap;
+ struct mbuf **mbp;
+ char **bposp;
+{
+ register struct mbuf *mb = *mbp, *mb2;
+ register char *bpos = *bposp;
+ register u_long *tl;
+
+ if (before_ret) {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ } else {
+ nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ txdr_hyper(&(before_vap->va_size), tl);
+ tl += 2;
+ txdr_nfsv3time(&(before_vap->va_mtime), tl);
+ tl += 2;
+ txdr_nfsv3time(&(before_vap->va_ctime), tl);
+ }
+ *bposp = bpos;
+ *mbp = mb;
+ nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
+}
+
+void
+nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
+ struct nfsrv_descript *nfsd;
+ int after_ret;
+ struct vattr *after_vap;
+ struct mbuf **mbp;
+ char **bposp;
+{
+ register struct mbuf *mb = *mbp, *mb2;
+ register char *bpos = *bposp;
+ register u_long *tl;
+ register struct nfs_fattr *fp;
+
+ if (after_ret) {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
+ *tl++ = nfs_true;
+ fp = (struct nfs_fattr *)tl;
+ nfsm_srvfattr(nfsd, after_vap, fp);
+ }
+ *mbp = mb;
+ *bposp = bpos;
+}
+
+void
+nfsm_srvfattr(nfsd, vap, fp)
+ register struct nfsrv_descript *nfsd;
+ register struct vattr *vap;
+ register struct nfs_fattr *fp;
+{
+
+ fp->fa_nlink = txdr_unsigned(vap->va_nlink);
+ fp->fa_uid = txdr_unsigned(vap->va_uid);
+ fp->fa_gid = txdr_unsigned(vap->va_gid);
+ if (nfsd->nd_flag & ND_NFSV3) {
+ fp->fa_type = vtonfsv3_type(vap->va_type);
+ fp->fa_mode = vtonfsv3_mode(vap->va_mode);
+ txdr_hyper(&vap->va_size, &fp->fa3_size);
+ txdr_hyper(&vap->va_bytes, &fp->fa3_used);
+ fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
+ fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
+ fp->fa3_fsid.nfsuquad[0] = 0;
+ fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
+ fp->fa3_fileid.nfsuquad[0] = 0;
+ fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
+ txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
+ txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
+ txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
+ } else {
+ fp->fa_type = vtonfsv2_type(vap->va_type);
+ fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
+ fp->fa2_size = txdr_unsigned(vap->va_size);
+ fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
+ if (vap->va_type == VFIFO)
+ fp->fa2_rdev = 0xffffffff;
+ else
+ fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
+ fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
+ fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
+ fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
+ txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
+ txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
+ txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
+ }
+}
+
+/*
* nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
* - look up fsid in mount list (if not found ret error)
* - get vp and export rights by calling VFS_FHTOVP()
@@ -1094,7 +1661,7 @@ nfsm_adj(mp, len, nul)
* - if not lockflag unlock it with VOP_UNLOCK()
*/
int
-nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
+nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
fhandle_t *fhp;
int lockflag;
struct vnode **vpp;
@@ -1102,6 +1669,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
struct nfssvc_sock *slp;
struct mbuf *nam;
int *rdonlyp;
+ int kerbflag;
{
register struct mount *mp;
register struct nfsuid *uidp;
@@ -1120,19 +1688,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
* Check/setup credentials.
*/
if (exflags & MNT_EXKERB) {
- for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
- uidp = uidp->nu_hash.le_next) {
- if (uidp->nu_uid == cred->cr_uid)
- break;
- }
- if (uidp == 0) {
+ if (!kerbflag) {
vput(*vpp);
- return (NQNFS_AUTHERR);
+ return (NFSERR_AUTHERR | AUTH_TOOWEAK);
}
- cred->cr_uid = uidp->nu_cr.cr_uid;
- for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
- cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
- cred->cr_ngroups = i;
+ } else if (kerbflag) {
+ vput(*vpp);
+ return (NFSERR_AUTHERR | AUTH_TOOWEAK);
} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
cred->cr_uid = credanon->cr_uid;
for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
@@ -1194,6 +1756,145 @@ netaddr_match(family, haddr, nam)
return (0);
}
+static nfsuint64 nfs_nullcookie = { 0, 0 };
+/*
+ * This function finds the directory cookie that corresponds to the
+ * logical byte offset given.
+ */
+nfsuint64 *
+nfs_getcookie(np, off, add)
+ register struct nfsnode *np;
+ off_t off;
+ int add;
+{
+ register struct nfsdmap *dp, *dp2;
+ register int pos;
+
+ pos = off / NFS_DIRBLKSIZ;
+ if (pos == 0) {
+#ifdef DIAGNOSTIC
+ if (add)
+ panic("nfs getcookie add at 0");
+#endif
+ return (&nfs_nullcookie);
+ }
+ pos--;
+ dp = np->n_cookies.lh_first;
+ if (!dp) {
+ if (add) {
+ MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
+ M_NFSDIROFF, M_WAITOK);
+ dp->ndm_eocookie = 0;
+ LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
+ } else
+ return ((nfsuint64 *)0);
+ }
+ while (pos >= NFSNUMCOOKIES) {
+ pos -= NFSNUMCOOKIES;
+ if (dp->ndm_list.le_next) {
+ if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
+ pos >= dp->ndm_eocookie)
+ return ((nfsuint64 *)0);
+ dp = dp->ndm_list.le_next;
+ } else if (add) {
+ MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
+ M_NFSDIROFF, M_WAITOK);
+ dp2->ndm_eocookie = 0;
+ LIST_INSERT_AFTER(dp, dp2, ndm_list);
+ dp = dp2;
+ } else
+ return ((nfsuint64 *)0);
+ }
+ if (pos >= dp->ndm_eocookie) {
+ if (add)
+ dp->ndm_eocookie = pos + 1;
+ else
+ return ((nfsuint64 *)0);
+ }
+ return (&dp->ndm_cookies[pos]);
+}
+
+/*
+ * Invalidate cached directory information, except for the actual directory
+ * blocks (which are invalidated separately).
+ * Done mainly to avoid the use of stale offset cookies.
+ */
+void
+nfs_invaldir(vp)
+ register struct vnode *vp;
+{
+ register struct nfsnode *np = VTONFS(vp);
+
+#ifdef DIAGNOSTIC
+ if (vp->v_type != VDIR)
+ panic("nfs: invaldir not dir");
+#endif
+ np->n_direofoffset = 0;
+ np->n_cookieverf.nfsuquad[0] = 0;
+ np->n_cookieverf.nfsuquad[1] = 0;
+ if (np->n_cookies.lh_first)
+ np->n_cookies.lh_first->ndm_eocookie = 0;
+}
+
+/*
+ * The write verifier has changed (probably due to a server reboot), so all
+ * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
+ * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
+ * flag. Once done the new write verifier can be set for the mount point.
+ */
+void
+nfs_clearcommit(mp)
+ struct mount *mp;
+{
+ register struct vnode *vp, *nvp;
+ register struct buf *bp, *nbp;
+ int s;
+
+ s = splbio();
+loop:
+ for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
+ if (vp->v_mount != mp) /* Paranoia */
+ goto loop;
+ nvp = vp->v_mntvnodes.le_next;
+ for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
+ nbp = bp->b_vnbufs.le_next;
+ if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
+ == (B_DELWRI | B_NEEDCOMMIT))
+ bp->b_flags &= ~B_NEEDCOMMIT;
+ }
+ }
+ splx(s);
+}
+
+/*
+ * Map errnos to NFS error numbers. For Version 3 also filter out error
+ * numbers not specified for the associated procedure.
+ */
+int
+nfsrv_errmap(nd, err)
+ struct nfsrv_descript *nd;
+ register int err;
+{
+ register short *defaulterrp, *errp;
+
+ if (nd->nd_flag & ND_NFSV3) {
+ if (nd->nd_procnum <= NFSPROC_COMMIT) {
+ errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
+ while (*++errp) {
+ if (*errp == err)
+ return (err);
+ else if (*errp > err)
+ break;
+ }
+ return ((int)*defaulterrp);
+ } else
+ return (err & 0xffff);
+ }
+ if (err <= ELAST)
+ return ((int)nfsrv_v2errmap[err - 1]);
+ return (NFSERR_IO);
+}
+
int
nfsrv_vmio( struct vnode *vp) {
vm_object_t object;
diff --git a/sys/nfs/nfs_common.h b/sys/nfs/nfs_common.h
index 030a985b40d1..9e89c57b1c08 100644
--- a/sys/nfs/nfs_common.h
+++ b/sys/nfs/nfs_common.h
@@ -34,12 +34,13 @@
* SUCH DAMAGE.
*
* @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93
- * $Id: nfsm_subs.h,v 1.5 1994/10/17 17:47:42 phk Exp $
+ * $Id: nfsm_subs.h,v 1.6 1995/05/30 08:12:51 rgrimes Exp $
*/
#ifndef _NFS_NFSM_SUBS_H_
#define _NFS_NFSM_SUBS_H_
+
/*
* These macros do strange and peculiar things to mbuf chains for
* the assistance of the nfs code. To attempt to use them for any
@@ -90,49 +91,153 @@ extern struct mbuf *nfsm_reqh();
mb->m_len += (s); \
bpos += (s); }
-#define nfsm_dissect(a,c,s) \
+#define nfsm_dissect(a, c, s) \
{ t1 = mtod(md, caddr_t)+md->m_len-dpos; \
if (t1 >= (s)) { \
(a) = (c)(dpos); \
dpos += (s); \
+ } else if (t1 = nfsm_disct(&md, &dpos, (s), t1, &cp2)) { \
+ error = t1; \
+ m_freem(mrep); \
+ goto nfsmout; \
} else { \
- error = nfsm_disct(&md, &dpos, (s), t1, &cp2); \
- if (error) { \
- m_freem(mrep); \
+ (a) = (c)cp2; \
+ } }
+
+#define nfsm_fhtom(v, v3) \
+ { if (v3) { \
+ t2 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; \
+ if (t2 <= M_TRAILINGSPACE(mb)) { \
+ nfsm_build(tl, u_long *, t2); \
+ *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); \
+ *(tl + ((t2>>2) - 2)) = 0; \
+ bcopy((caddr_t)VTONFS(v)->n_fhp,(caddr_t)tl, \
+ VTONFS(v)->n_fhsize); \
+ } else if (t2 = nfsm_strtmbuf(&mb, &bpos, \
+ (caddr_t)VTONFS(v)->n_fhp, VTONFS(v)->n_fhsize)) { \
+ error = t2; \
+ m_freem(mreq); \
goto nfsmout; \
- } else { \
- (a) = (c)cp2; \
} \
+ } else { \
+ nfsm_build(cp, caddr_t, NFSX_V2FH); \
+ bcopy((caddr_t)VTONFS(v)->n_fhp, cp, NFSX_V2FH); \
} }
-#define nfsm_fhtom(v) \
- nfsm_build(cp,caddr_t,NFSX_FH); \
- bcopy((caddr_t)&(VTONFS(v)->n_fh), cp, NFSX_FH)
+#define nfsm_srvfhtom(f, v3) \
+ { if (v3) { \
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FH); \
+ *tl++ = txdr_unsigned(NFSX_V3FH); \
+ bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \
+ } else { \
+ nfsm_build(cp, caddr_t, NFSX_V2FH); \
+ bcopy((caddr_t)(f), cp, NFSX_V2FH); \
+ } }
-#define nfsm_srvfhtom(f) \
- nfsm_build(cp,caddr_t,NFSX_FH); \
- bcopy((caddr_t)(f), cp, NFSX_FH)
+#define nfsm_srvpostop_fh(f) \
+ { nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED + NFSX_V3FH); \
+ *tl++ = nfs_true; \
+ *tl++ = txdr_unsigned(NFSX_V3FH); \
+ bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \
+ }
-#define nfsm_mtofh(d,v) \
- { struct nfsnode *np; nfsv2fh_t *fhp; \
- nfsm_dissect(fhp,nfsv2fh_t *,NFSX_FH); \
- error = nfs_nget((d)->v_mount, fhp, &np); \
- if (error) { \
- m_freem(mrep); \
- goto nfsmout; \
+#define nfsm_mtofh(d, v, v3, f) \
+ { struct nfsnode *ttnp; nfsfh_t *ttfhp; int ttfhsize; \
+ if (v3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (f) = fxdr_unsigned(int, *tl); \
+ } else \
+ (f) = 1; \
+ if (f) { \
+ nfsm_getfh(ttfhp, ttfhsize, (v3)); \
+ if (t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \
+ &ttnp)) { \
+ error = t1; \
+ m_freem(mrep); \
+ goto nfsmout; \
+ } \
+ (v) = NFSTOV(ttnp); \
+ } \
+ if (v3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (f) \
+ (f) = fxdr_unsigned(int, *tl); \
+ else if (fxdr_unsigned(int, *tl)) \
+ nfsm_adv(NFSX_V3FATTR); \
} \
- (v) = NFSTOV(np); \
- nfsm_loadattr(v, (struct vattr *)0); \
+ if (f) \
+ nfsm_loadattr((v), (struct vattr *)0); \
}
-#define nfsm_loadattr(v,a) \
- { struct vnode *tvp = (v); \
- error = nfs_loadattrcache(&tvp, &md, &dpos, (a)); \
- if (error) { \
+#define nfsm_getfh(f, s, v3) \
+ { if (v3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (((s) = fxdr_unsigned(int, *tl)) <= 0 || \
+ (s) > NFSX_V3FHMAX) { \
+ m_freem(mrep); \
+ error = EBADRPC; \
+ goto nfsmout; \
+ } \
+ } else \
+ (s) = NFSX_V2FH; \
+ nfsm_dissect((f), nfsfh_t *, nfsm_rndup(s)); }
+
+#define nfsm_loadattr(v, a) \
+ { struct vnode *ttvp = (v); \
+ if (t1 = nfs_loadattrcache(&ttvp, &md, &dpos, (a))) { \
+ error = t1; \
m_freem(mrep); \
goto nfsmout; \
} \
- (v) = tvp; }
+ (v) = ttvp; }
+
+#define nfsm_postop_attr(v, f) \
+ { struct vnode *ttvp = (v); \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if ((f) = fxdr_unsigned(int, *tl)) { \
+ if (t1 = nfs_loadattrcache(&ttvp, &md, &dpos, \
+ (struct vattr *)0)) { \
+ error = t1; \
+ (f) = 0; \
+ m_freem(mrep); \
+ goto nfsmout; \
+ } \
+ (v) = ttvp; \
+ } }
+
+/* Used as (f) for nfsm_wcc_data() */
+#define NFSV3_WCCRATTR 0
+#define NFSV3_WCCCHK 1
+
+#define nfsm_wcc_data(v, f) \
+ { int ttattrf, ttretf = 0; \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED); \
+ if (f) \
+ ttretf = (VTONFS(v)->n_mtime == \
+ fxdr_unsigned(u_long, *(tl + 2))); \
+ } \
+ nfsm_postop_attr((v), ttattrf); \
+ if (f) { \
+ (f) = ttretf; \
+ } else { \
+ (f) = ttattrf; \
+ } }
+
+#define nfsm_v3sattr(s, a, u, g) \
+ { (s)->sa_modetrue = nfs_true; \
+ (s)->sa_mode = vtonfsv3_mode((a)->va_mode); \
+ (s)->sa_uidtrue = nfs_true; \
+ (s)->sa_uid = txdr_unsigned(u); \
+ (s)->sa_gidtrue = nfs_true; \
+ (s)->sa_gid = txdr_unsigned(g); \
+ (s)->sa_sizefalse = nfs_false; \
+ (s)->sa_atimetype = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); \
+ txdr_nfsv3time(&(a)->va_atime, &(s)->sa_atime); \
+ (s)->sa_mtimetype = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); \
+ txdr_nfsv3time(&(a)->va_mtime, &(s)->sa_mtime); \
+ }
#define nfsm_strsiz(s,m) \
{ nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \
@@ -149,16 +254,27 @@ extern struct mbuf *nfsm_reqh();
nfsm_reply(0); \
} }
+#define nfsm_srvnamesiz(s) \
+ { nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \
+ if (((s) = fxdr_unsigned(long,*tl)) > NFS_MAXNAMLEN) \
+ error = NFSERR_NAMETOL; \
+ if ((s) <= 0) \
+ error = EBADRPC; \
+ if (error) \
+ nfsm_reply(0); \
+ }
+
#define nfsm_mtouio(p,s) \
if ((s) > 0 && \
- (error = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \
+ (t1 = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \
+ error = t1; \
m_freem(mrep); \
goto nfsmout; \
}
#define nfsm_uiotom(p,s) \
- error = nfsm_uiotombuf((p),&mb,(s),&bpos); \
- if (error) { \
+ if (t1 = nfsm_uiotombuf((p),&mb,(s),&bpos)) { \
+ error = t1; \
m_freem(mreq); \
goto nfsmout; \
}
@@ -172,10 +288,13 @@ extern struct mbuf *nfsm_reqh();
#define nfsm_rndup(a) (((a)+3)&(~0x3))
#define nfsm_request(v, t, p, c) \
- error = nfs_request((v), mreq, (t), (p), \
- (c), &mrep, &md, &dpos); \
- if (error) \
- goto nfsmout
+ if (error = nfs_request((v), mreq, (t), (p), \
+ (c), &mrep, &md, &dpos)) { \
+ if (error & NFSERR_RETERR) \
+ error &= ~NFSERR_RETERR; \
+ else \
+ goto nfsmout; \
+ }
#define nfsm_strtom(a,s,m) \
if ((s) > (m)) { \
@@ -189,12 +308,10 @@ extern struct mbuf *nfsm_reqh();
*tl++ = txdr_unsigned(s); \
*(tl+((t2>>2)-2)) = 0; \
bcopy((caddr_t)(a), (caddr_t)tl, (s)); \
- } else { \
- error = nfsm_strtmbuf(&mb, &bpos, (a), (s)); \
- if (error) { \
- m_freem(mreq); \
- goto nfsmout; \
- } \
+ } else if (t2 = nfsm_strtmbuf(&mb, &bpos, (a), (s))) { \
+ error = t2; \
+ m_freem(mreq); \
+ goto nfsmout; \
}
#define nfsm_srvdone \
@@ -204,33 +321,53 @@ extern struct mbuf *nfsm_reqh();
#define nfsm_reply(s) \
{ \
nfsd->nd_repstat = error; \
- if (error) \
- (void) nfs_rephead(0, nfsd, error, cache, &frev, \
+ if (error && !(nfsd->nd_flag & ND_NFSV3)) \
+ (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \
mrq, &mb, &bpos); \
else \
- (void) nfs_rephead((s), nfsd, error, cache, &frev, \
+ (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \
mrq, &mb, &bpos); \
m_freem(mrep); \
mreq = *mrq; \
- if (error) \
+ if (error && (!(nfsd->nd_flag & ND_NFSV3) || \
+ error == EBADRPC)) \
return(0); \
}
+#define nfsm_writereply(s, v3) \
+ { \
+ nfsd->nd_repstat = error; \
+ if (error && !(v3)) \
+ (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \
+ &mreq, &mb, &bpos); \
+ else \
+ (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \
+ &mreq, &mb, &bpos); \
+ }
+
#define nfsm_adv(s) \
- t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+ { t1 = mtod(md, caddr_t)+md->m_len-dpos; \
if (t1 >= (s)) { \
dpos += (s); \
- } else { \
- error = nfs_adv(&md, &dpos, (s), t1); \
- if (error) { \
- m_freem(mrep); \
- goto nfsmout; \
- } \
- }
+ } else if (t1 = nfs_adv(&md, &dpos, (s), t1)) { \
+ error = t1; \
+ m_freem(mrep); \
+ goto nfsmout; \
+ } }
#define nfsm_srvmtofh(f) \
- nfsm_dissect(tl, u_long *, NFSX_FH); \
- bcopy((caddr_t)tl, (caddr_t)f, NFSX_FH)
+ { if (nfsd->nd_flag & ND_NFSV3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \
+ error = EBADRPC; \
+ nfsm_reply(0); \
+ } \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_V3FH); \
+ bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \
+ if ((nfsd->nd_flag & ND_NFSV3) == 0) \
+ nfsm_adv(NFSX_V2FH - NFSX_V3FH); \
+ }
#define nfsm_clget \
if (bp >= be) { \
@@ -246,41 +383,57 @@ extern struct mbuf *nfsm_reqh();
} \
tl = (u_long *)bp
-#define nfsm_srvfillattr \
- fp->fa_type = vtonfs_type(vap->va_type); \
- fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode); \
- fp->fa_nlink = txdr_unsigned(vap->va_nlink); \
- fp->fa_uid = txdr_unsigned(vap->va_uid); \
- fp->fa_gid = txdr_unsigned(vap->va_gid); \
- if (nfsd->nd_nqlflag == NQL_NOVAL) { \
- fp->fa_nfsblocksize = txdr_unsigned(vap->va_blocksize); \
- if (vap->va_type == VFIFO) \
- fp->fa_nfsrdev = 0xffffffff; \
- else \
- fp->fa_nfsrdev = txdr_unsigned(vap->va_rdev); \
- fp->fa_nfsfsid = txdr_unsigned(vap->va_fsid); \
- fp->fa_nfsfileid = txdr_unsigned(vap->va_fileid); \
- fp->fa_nfssize = txdr_unsigned(vap->va_size); \
- fp->fa_nfsblocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); \
- txdr_nfstime(&vap->va_atime, &fp->fa_nfsatime); \
- txdr_nfstime(&vap->va_mtime, &fp->fa_nfsmtime); \
- txdr_nfstime(&vap->va_ctime, &fp->fa_nfsctime); \
- } else { \
- fp->fa_nqblocksize = txdr_unsigned(vap->va_blocksize); \
- if (vap->va_type == VFIFO) \
- fp->fa_nqrdev = 0xffffffff; \
- else \
- fp->fa_nqrdev = txdr_unsigned(vap->va_rdev); \
- fp->fa_nqfsid = txdr_unsigned(vap->va_fsid); \
- fp->fa_nqfileid = txdr_unsigned(vap->va_fileid); \
- txdr_hyper(&vap->va_size, &fp->fa_nqsize); \
- txdr_hyper(&vap->va_bytes, &fp->fa_nqbytes); \
- txdr_nqtime(&vap->va_atime, &fp->fa_nqatime); \
- txdr_nqtime(&vap->va_mtime, &fp->fa_nqmtime); \
- txdr_nqtime(&vap->va_ctime, &fp->fa_nqctime); \
- fp->fa_nqflags = txdr_unsigned(vap->va_flags); \
- fp->fa_nqgen = txdr_unsigned(vap->va_gen); \
- txdr_hyper(&vap->va_filerev, &fp->fa_nqfilerev); \
- }
+#define nfsm_srvfillattr(a, f) \
+ nfsm_srvfattr(nfsd, (a), (f))
+
+#define nfsm_srvwcc_data(br, b, ar, a) \
+ nfsm_srvwcc(nfsd, (br), (b), (ar), (a), &mb, &bpos)
+
+#define nfsm_srvpostop_attr(r, a) \
+ nfsm_srvpostopattr(nfsd, (r), (a), &mb, &bpos)
+
+#define nfsm_srvsattr(a) \
+ { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (a)->va_mode = nfstov_mode(*tl); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (a)->va_uid = fxdr_unsigned(uid_t, *tl); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (a)->va_gid = fxdr_unsigned(gid_t, *tl); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \
+ fxdr_hyper(tl, &(a)->va_size); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ switch (fxdr_unsigned(int, *tl)) { \
+ case NFSV3SATTRTIME_TOCLIENT: \
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \
+ fxdr_nfsv3time(tl, &(a)->va_atime); \
+ break; \
+ case NFSV3SATTRTIME_TOSERVER: \
+ (a)->va_atime.ts_sec = time.tv_sec; \
+ (a)->va_atime.ts_nsec = time.tv_usec * 1000; \
+ break; \
+ }; \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ switch (fxdr_unsigned(int, *tl)) { \
+ case NFSV3SATTRTIME_TOCLIENT: \
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \
+ fxdr_nfsv3time(tl, &(a)->va_mtime); \
+ break; \
+ case NFSV3SATTRTIME_TOSERVER: \
+ (a)->va_mtime.ts_sec = time.tv_sec; \
+ (a)->va_mtime.ts_nsec = time.tv_usec * 1000; \
+ break; \
+ }; }
#endif
diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c
index e5315f449b14..c002cea01bd5 100644
--- a/sys/nfs/nfs_node.c
+++ b/sys/nfs/nfs_node.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_node.c 8.2 (Berkeley) 12/30/93
- * $Id: nfs_node.c,v 1.7 1994/10/17 17:47:33 phk Exp $
+ * $Id: nfs_node.c,v 1.8 1995/03/16 18:15:36 bde Exp $
*/
#include <sys/param.h>
@@ -47,14 +47,12 @@
#include <sys/malloc.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsnode.h>
#include <nfs/nfsmount.h>
#include <nfs/nqnfs.h>
-#define NFSNOHASH(fhsum) \
- (&nfsnodehashtbl[(fhsum) & nfsnodehash])
LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
u_long nfsnodehash;
@@ -79,19 +77,20 @@ nfs_nhinit()
/*
* Compute an entry in the NFS hash table structure
*/
-struct nfsnodehashhead *
-nfs_hash(fhp)
- register nfsv2fh_t *fhp;
+u_long
+nfs_hash(fhp, fhsize)
+ register nfsfh_t *fhp;
+ int fhsize;
{
register u_char *fhpp;
register u_long fhsum;
- int i;
+ register int i;
fhpp = &fhp->fh_bytes[0];
fhsum = 0;
- for (i = 0; i < NFSX_FH; i++)
+ for (i = 0; i < fhsize; i++)
fhsum += *fhpp++;
- return (NFSNOHASH(fhsum));
+ return (fhsum);
}
/*
@@ -101,9 +100,10 @@ nfs_hash(fhp)
* nfsnode structure is returned.
*/
int
-nfs_nget(mntp, fhp, npp)
+nfs_nget(mntp, fhp, fhsize, npp)
struct mount *mntp;
- register nfsv2fh_t *fhp;
+ register nfsfh_t *fhp;
+ int fhsize;
struct nfsnode **npp;
{
register struct nfsnode *np;
@@ -112,11 +112,11 @@ nfs_nget(mntp, fhp, npp)
struct vnode *nvp;
int error;
- nhpp = nfs_hash(fhp);
+ nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
loop:
for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
- if (mntp != NFSTOV(np)->v_mount ||
- bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH))
+ if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize ||
+ bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize))
continue;
vp = NFSTOV(np);
if (vget(vp, 1))
@@ -131,27 +131,26 @@ loop:
}
vp = nvp;
MALLOC(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
+ bzero((caddr_t)np, sizeof *np);
vp->v_data = np;
np->n_vnode = vp;
/*
* Insert the nfsnode in the hash queue for its new file handle
*/
- np->n_flag = 0;
LIST_INSERT_HEAD(nhpp, np, n_hash);
- bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
- np->n_attrstamp = 0;
- np->n_direofoffset = 0;
- np->n_sillyrename = (struct sillyrename *)0;
- np->n_size = 0;
- np->n_mtime = 0;
- np->n_lockf = 0;
- if (VFSTONFS(mntp)->nm_flag & NFSMNT_NQNFS) {
- np->n_brev = 0;
- np->n_lrev = 0;
- np->n_expiry = (time_t)0;
- np->n_timer.cqe_next = (struct nfsnode *)0;
- }
+ if (fhsize > NFS_SMALLFH) {
+ MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK);
+ } else
+ np->n_fhp = &np->n_fh;
+ bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
+ np->n_fhsize = fhsize;
*npp = np;
+
+ /*
+ * Lock the new nfsnode.
+ */
+ VOP_LOCK(vp);
+
return (0);
}
@@ -168,7 +167,10 @@ nfs_inactive(ap)
np = VTONFS(ap->a_vp);
if (prtactive && ap->a_vp->v_usecount != 0)
vprint("nfs_inactive: pushing active", ap->a_vp);
- sp = np->n_sillyrename;
+ if (ap->a_vp->v_type != VDIR)
+ sp = np->n_sillyrename;
+ else
+ sp = (struct sillyrename *)0;
np->n_sillyrename = (struct sillyrename *)0;
if (sp) {
/*
@@ -178,9 +180,7 @@ nfs_inactive(ap)
nfs_removeit(sp);
crfree(sp->s_cred);
vrele(sp->s_dvp);
-#ifdef SILLYSEPARATE
- free((caddr_t)sp, M_NFSREQ);
-#endif
+ FREE((caddr_t)sp, M_NFSREQ);
}
np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED |
NQNFSNONCACHE | NQNFSWRITE);
@@ -199,6 +199,7 @@ nfs_reclaim(ap)
register struct vnode *vp = ap->a_vp;
register struct nfsnode *np = VTONFS(vp);
register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ register struct nfsdmap *dp, *dp2;
if (prtactive && vp->v_usecount != 0)
vprint("nfs_reclaim: pushing active", vp);
@@ -211,6 +212,24 @@ nfs_reclaim(ap)
if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_timer.cqe_next != 0) {
CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
}
+
+ /*
+ * Free up any directory cookie structures and
+ * large file handle structures that might be associated with
+ * this nfs node.
+ */
+ if (vp->v_type == VDIR) {
+ dp = np->n_cookies.lh_first;
+ while (dp) {
+ dp2 = dp;
+ dp = dp->ndm_list.le_next;
+ FREE((caddr_t)dp2, M_NFSDIROFF);
+ }
+ }
+ if (np->n_fhsize > NFS_SMALLFH) {
+ FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
+ }
+
cache_purge(vp);
FREE(vp->v_data, M_NFSNODE);
vp->v_data = (void *)0;
@@ -227,6 +246,7 @@ nfs_lock(ap)
} */ *ap;
{
register struct vnode *vp = ap->a_vp;
+ struct nfsnode *np = VTONFS(vp);
/*
* Ugh, another place where interruptible mounts will get hung.
@@ -239,6 +259,33 @@ nfs_lock(ap)
}
if (vp->v_tag == VT_NON)
return (ENOENT);
+
+#if 0
+ /*
+ * Only lock regular files. If a server crashed while we were
+ * holding a directory lock, we could easily end up sleeping
+ * until the server rebooted while holding a lock on the root.
+ * Locks are only needed for protecting critical sections in
+ * VMIO at the moment.
+ * New vnodes will have type VNON but they should be locked
+ * since they may become VREG. This is checked in loadattrcache
+ * and unwanted locks are released there.
+ */
+ if (vp->v_type == VREG || vp->v_type == VNON) {
+ while (np->n_flag & NLOCKED) {
+ np->n_flag |= NWANTED;
+ (void) tsleep((caddr_t) np, PINOD, "nfslck2", 0);
+ /*
+ * If the vnode has transmuted into a VDIR while we
+ * were asleep, then skip the lock.
+ */
+ if (vp->v_type != VREG && vp->v_type != VNON)
+ return (0);
+ }
+ np->n_flag |= NLOCKED;
+ }
+#endif
+
return (0);
}
@@ -251,6 +298,20 @@ nfs_unlock(ap)
struct vnode *a_vp;
} */ *ap;
{
+#if 0
+ struct vnode* vp = ap->a_vp;
+ struct nfsnode* np = VTONFS(vp);
+
+ if (vp->v_type == VREG || vp->v_type == VNON) {
+ if (!(np->n_flag & NLOCKED))
+ panic("nfs_unlock: nfsnode not locked");
+ np->n_flag &= ~NLOCKED;
+ if (np->n_flag & NWANTED) {
+ np->n_flag &= ~NWANTED;
+ wakeup((caddr_t) np);
+ }
+ }
+#endif
return (0);
}
@@ -264,8 +325,7 @@ nfs_islocked(ap)
struct vnode *a_vp;
} */ *ap;
{
-
- return (0);
+ return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0;
}
/*
diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c
index 81571de2764a..d953699dd91b 100644
--- a/sys/nfs/nfs_nqlease.c
+++ b/sys/nfs/nfs_nqlease.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_nqlease.c 8.3 (Berkeley) 1/4/94
- * $Id: nfs_nqlease.c,v 1.10 1995/02/15 03:39:58 davidg Exp $
+ * $Id: nfs_nqlease.c,v 1.11 1995/05/30 08:12:36 rgrimes Exp $
*/
/*
@@ -66,7 +66,7 @@
#include <netinet/in.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/xdr_subs.h>
@@ -75,7 +75,6 @@
#include <nfs/nfsmount.h>
time_t nqnfsstarttime = (time_t)0;
-u_long nqnfs_prog, nqnfs_vers;
int nqsrv_clockskew = NQ_CLOCKSKEW;
int nqsrv_writeslack = NQ_WRITESLACK;
int nqsrv_maxlease = NQ_MAXLEASE;
@@ -91,14 +90,13 @@ struct mbuf *nfsm_rpchead();
*/
int nqnfs_piggy[NFS_NPROCS] = {
0,
- NQL_READ,
- NQL_WRITE,
0,
- NQL_READ,
- NQL_READ,
- NQL_READ,
+ ND_WRITE,
+ ND_READ,
0,
- NQL_WRITE,
+ ND_READ,
+ ND_READ,
+ ND_WRITE,
0,
0,
0,
@@ -106,24 +104,30 @@ int nqnfs_piggy[NFS_NPROCS] = {
0,
0,
0,
- NQL_READ,
0,
- NQL_READ,
+ ND_READ,
+ ND_READ,
+ 0,
+ 0,
+ 0,
+ 0,
0,
0,
0,
0,
};
-extern nfstype nfs_type[9];
+extern nfstype nfsv2_type[9];
+extern nfstype nfsv3_type[9];
extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
extern int nfsd_waiting;
+extern struct nfsstats nfsstats;
#define TRUE 1
#define FALSE 0
/*
- * Get or check for a lease for "vp", based on NQL_CHECK flag.
+ * Get or check for a lease for "vp", based on ND_CHECK flag.
* The rules are as follows:
* - if a current non-caching lease, reply non-caching
* - if a current lease for same host only, extend lease
@@ -146,11 +150,12 @@ extern int nfsd_waiting;
* queue yet. (Ditto for the splsoftclock() and splx(s) calls)
*/
int
-nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
+nqsrv_getlease(vp, duration, flags, slp, procp, nam, cachablep, frev, cred)
struct vnode *vp;
u_long *duration;
int flags;
- struct nfsd *nd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
struct mbuf *nam;
int *cachablep;
u_quad_t *frev;
@@ -169,13 +174,13 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
return (0);
if (*duration > nqsrv_maxlease)
*duration = nqsrv_maxlease;
- error = VOP_GETATTR(vp, &vattr, cred, nd->nd_procp);
+ error = VOP_GETATTR(vp, &vattr, cred, procp);
if (error)
return (error);
*frev = vattr.va_filerev;
s = splsoftclock();
tlp = vp->v_lease;
- if ((flags & NQL_CHECK) == 0)
+ if ((flags & ND_CHECK) == 0)
nfsstats.srvnqnfs_getleases++;
if (tlp == (struct nqlease *)0) {
@@ -205,12 +210,12 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
if (lp) {
if ((lp->lc_flag & LC_NONCACHABLE) ||
(lp->lc_morehosts == (struct nqm *)0 &&
- nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host)))
+ nqsrv_cmpnam(slp, nam, &lp->lc_host)))
goto doreply;
- if ((flags & NQL_READ) && (lp->lc_flag & LC_WRITE) == 0) {
- if (flags & NQL_CHECK)
+ if ((flags & ND_READ) && (lp->lc_flag & LC_WRITE) == 0) {
+ if (flags & ND_CHECK)
goto doreply;
- if (nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host))
+ if (nqsrv_cmpnam(slp, nam, &lp->lc_host))
goto doreply;
i = 0;
if (lp->lc_morehosts) {
@@ -222,7 +227,7 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
ok = 0;
}
while (ok && (lph->lph_flag & LC_VALID)) {
- if (nqsrv_cmpnam(nd->nd_slp, nam, lph))
+ if (nqsrv_cmpnam(slp, nam, lph))
goto doreply;
if (++i == LC_MOREHOSTSIZ) {
i = 0;
@@ -242,12 +247,12 @@ nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
bzero((caddr_t)*lphp, sizeof (struct nqm));
lph = (*lphp)->lpm_hosts;
}
- nqsrv_addhost(lph, nd->nd_slp, nam);
+ nqsrv_addhost(lph, slp, nam);
nqsrv_unlocklease(lp);
} else {
lp->lc_flag |= LC_NONCACHABLE;
nqsrv_locklease(lp);
- nqsrv_send_eviction(vp, lp, nd->nd_slp, nam, cred);
+ nqsrv_send_eviction(vp, lp, slp, nam, cred);
nqsrv_waitfor_expiry(lp);
nqsrv_unlocklease(lp);
}
@@ -255,20 +260,20 @@ doreply:
/*
* Update the lease and return
*/
- if ((flags & NQL_CHECK) == 0)
+ if ((flags & ND_CHECK) == 0)
nqsrv_instimeq(lp, *duration);
if (lp->lc_flag & LC_NONCACHABLE)
*cachablep = 0;
else {
*cachablep = 1;
- if (flags & NQL_WRITE)
+ if (flags & ND_WRITE)
lp->lc_flag |= LC_WRITTEN;
}
splx(s);
return (0);
}
splx(s);
- if (flags & NQL_CHECK)
+ if (flags & ND_CHECK)
return (0);
/*
@@ -285,9 +290,9 @@ doreply:
}
MALLOC(lp, struct nqlease *, sizeof (struct nqlease), M_NQLEASE, M_WAITOK);
bzero((caddr_t)lp, sizeof (struct nqlease));
- if (flags & NQL_WRITE)
+ if (flags & ND_WRITE)
lp->lc_flag |= (LC_WRITE | LC_WRITTEN);
- nqsrv_addhost(&lp->lc_host, nd->nd_slp, nam);
+ nqsrv_addhost(&lp->lc_host, slp, nam);
lp->lc_vp = vp;
lp->lc_fsid = fh.fh_fsid;
bcopy(fh.fh_fid.fid_data, lp->lc_fiddata,
@@ -308,9 +313,12 @@ doreply:
/*
* Local lease check for server syscalls.
* Just set up args and let nqsrv_getlease() do the rest.
+ * nqnfs_vop_lease_check() is the VOP_LEASE() form of the same routine.
+ * Ifdef'd code in nfsnode.h renames these routines to whatever a particular
+ * OS needs.
*/
void
-nfs_lease_check(vp, p, cred, flag)
+nqnfs_lease_check(vp, p, cred, flag)
struct vnode *vp;
struct proc *p;
struct ucred *cred;
@@ -318,14 +326,31 @@ nfs_lease_check(vp, p, cred, flag)
{
u_long duration = 0;
int cache;
- struct nfsd nfsd;
u_quad_t frev;
- nfsd.nd_slp = NQLOCALSLP;
- nfsd.nd_procp = p;
- (void) nqsrv_getlease(vp, &duration, NQL_CHECK | flag, &nfsd,
- (struct mbuf *)0, &cache, &frev, cred);
+ (void) nqsrv_getlease(vp, &duration, ND_CHECK | flag, NQLOCALSLP,
+ p, (struct mbuf *)0, &cache, &frev, cred);
+}
+
+#ifdef HAS_VOPLEASE
+int
+nqnfs_vop_lease_check(ap)
+ struct vop_lease_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ struct ucred *a_cred;
+ int a_flag;
+ } */ *ap;
+{
+ u_long duration = 0;
+ int cache;
+ u_quad_t frev;
+
+ (void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag,
+ NQLOCALSLP, ap->a_p, (struct mbuf *)0, &cache, &frev, ap->a_cred);
+ return (0);
}
+#endif
/*
* Add a host to an nqhost structure for a lease.
@@ -486,9 +511,9 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred)
else
solockp = (int *)0;
nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
- NFSX_FH);
- nfsm_build(cp, caddr_t, NFSX_FH);
- bzero(cp, NFSX_FH);
+ NFSX_V3FH);
+ nfsm_build(cp, caddr_t, NFSX_V3FH);
+ bzero(cp, NFSX_V3FH);
fhp = (fhandle_t *)cp;
fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
VFS_VPTOFH(vp, &fhp->fh_fid);
@@ -502,8 +527,9 @@ nqsrv_send_eviction(vp, lp, slp, nam, cred)
printf("mbuf siz=%d\n",siz);
panic("Bad nfs svc reply");
}
- m = nfsm_rpchead(cred, TRUE, NQNFSPROC_EVICTED,
- RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0,
+ m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS),
+ NQNFSPROC_EVICTED,
+ RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
mreq, siz, &mheadend, &xid);
/*
* For stream protocols, prepend a Sun RPC
@@ -677,18 +703,21 @@ nqnfs_serverd()
* do the real work.
*/
int
-nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nqnfsrv_getlease(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
- register struct nfsv2_fattr *fp;
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register struct nfs_fattr *fp;
struct vattr va;
register struct vattr *vap = &va;
struct vnode *vp;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
register u_long *tl;
register long t1;
@@ -701,29 +730,29 @@ nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq)
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
flags = fxdr_unsigned(int, *tl++);
nfsd->nd_duration = fxdr_unsigned(int, *tl);
- error = nfsrv_fhtovp(fhp,
- TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
+ error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
+ (nfsd->nd_flag & ND_KERBAUTH));
if (error)
nfsm_reply(0);
- if (rdonly && flags == NQL_WRITE) {
+ if (rdonly && flags == ND_WRITE) {
error = EROFS;
nfsrv_vput(vp);
nfsm_reply(0);
}
- (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, nfsd,
+ (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, procp,
nam, &cache, &frev, cred);
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
+ error = VOP_GETATTR(vp, vap, cred, procp);
nfsrv_vput(vp);
- nfsm_reply(NFSX_NQFATTR + 4*NFSX_UNSIGNED);
- nfsm_build(tl, u_long *, 4*NFSX_UNSIGNED);
+ nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
+ nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(cache);
*tl++ = txdr_unsigned(nfsd->nd_duration);
txdr_hyper(&frev, tl);
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_NQFATTR);
- nfsm_srvfillattr;
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR);
+ nfsm_srvfillattr(vap, fp);
nfsm_srvdone;
}
@@ -732,23 +761,28 @@ nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq)
* client. Find the entry and expire it.
*/
int
-nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nqnfsrv_vacated(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register struct nqlease *lp;
register struct nqhost *lph;
struct nqlease *tlp = (struct nqlease *)0;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
register u_long *tl;
register long t1;
struct nqm *lphnext;
- int error = 0, i, len, ok, gotit = 0;
- char *cp2;
+ struct mbuf *mreq, *mb;
+ int error = 0, i, len, ok, gotit = 0, cache = 0;
+ char *cp2, *bpos;
+ u_quad_t frev;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
@@ -774,7 +808,7 @@ nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq)
lphnext = lp->lc_morehosts;
ok = 1;
while (ok && (lph->lph_flag & LC_VALID)) {
- if (nqsrv_cmpnam(nfsd->nd_slp, nam, lph)) {
+ if (nqsrv_cmpnam(slp, nam, lph)) {
lph->lph_flag |= LC_VACATED;
gotit++;
break;
@@ -812,7 +846,7 @@ nqnfs_getlease(vp, rwflag, cred, p)
{
register u_long *tl;
register caddr_t cp;
- register long t1;
+ register long t1, t2;
register struct nfsnode *np;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
caddr_t bpos, dpos, cp2;
@@ -823,16 +857,16 @@ nqnfs_getlease(vp, rwflag, cred, p)
u_quad_t frev;
nfsstats.rpccnt[NQNFSPROC_GETLEASE]++;
- mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_FH+2*NFSX_UNSIGNED,
+ mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED,
&bpos);
- nfsm_fhtom(vp);
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+ nfsm_fhtom(vp, 1);
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(rwflag);
*tl = txdr_unsigned(nmp->nm_leaseterm);
reqtime = time.tv_sec;
nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred);
np = VTONFS(vp);
- nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
+ nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
cachable = fxdr_unsigned(int, *tl++);
reqtime += fxdr_unsigned(int, *tl++);
if (reqtime > time.tv_sec) {
@@ -856,6 +890,8 @@ nqnfs_vacated(vp, cred)
register caddr_t cp;
register struct mbuf *m;
register int i;
+ register u_long *tl;
+ register long t1, t2;
caddr_t bpos;
u_long xid;
int error = 0;
@@ -865,16 +901,16 @@ nqnfs_vacated(vp, cred)
nmp = VFSTONFS(vp->v_mount);
nfsstats.rpccnt[NQNFSPROC_VACATED]++;
- nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH);
- nfsm_fhtom(vp);
+ nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_V3FH);
+ nfsm_fhtom(vp, 1);
m = mreq;
i = 0;
while (m) {
i += m->m_len;
m = m->m_next;
}
- m = nfsm_rpchead(cred, TRUE, NQNFSPROC_VACATED,
- RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0,
+ m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED,
+ RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
mreq, i, &mheadend, &xid);
if (nmp->nm_sotype == SOCK_STREAM) {
M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
@@ -888,6 +924,7 @@ nqnfs_vacated(vp, cred)
(void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep);
if (nmp->nm_soflags & PR_CONNREQUIRED)
nfs_sndunlock(&nmp->nm_flag);
+nfsmout:
return (error);
}
@@ -903,29 +940,37 @@ nqnfs_callback(nmp, mrep, md, dpos)
register struct vnode *vp;
register u_long *tl;
register long t1;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct nfsnode *np;
- struct nfsd nd;
- int error;
- char *cp2;
+ struct nfsd tnfsd;
+ struct nfssvc_sock *slp;
+ struct nfsrv_descript ndesc;
+ register struct nfsrv_descript *nfsd = &ndesc;
+ struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq;
+ int error = 0, cache = 0;
+ char *cp2, *bpos;
+ u_quad_t frev;
- nd.nd_mrep = mrep;
- nd.nd_md = md;
- nd.nd_dpos = dpos;
- error = nfs_getreq(&nd, FALSE);
+#ifndef nolint
+ slp = NULL;
+#endif
+ nfsd->nd_mrep = mrep;
+ nfsd->nd_md = md;
+ nfsd->nd_dpos = dpos;
+ error = nfs_getreq(nfsd, &tnfsd, FALSE);
if (error)
return (error);
- md = nd.nd_md;
- dpos = nd.nd_dpos;
- if (nd.nd_procnum != NQNFSPROC_EVICTED) {
+ md = nfsd->nd_md;
+ dpos = nfsd->nd_dpos;
+ if (nfsd->nd_procnum != NQNFSPROC_EVICTED) {
m_freem(mrep);
return (EPERM);
}
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
m_freem(mrep);
- error = nfs_nget(nmp->nm_mountp, &nfh, &np);
+ error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np);
if (error)
return (error);
vp = NFSTOV(np);
@@ -937,7 +982,7 @@ nqnfs_callback(nmp, mrep, md, dpos)
CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
}
}
- vrele(vp);
+ vput(vp);
nfsm_srvdone;
}
@@ -960,35 +1005,39 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
register struct nfsnode *np;
struct vnode *vp;
struct nfsreq myrep;
+ struct nfsuid *nuidp, *nnuidp;
int error = 0, vpid;
/*
* First initialize some variables
*/
- nqnfs_prog = txdr_unsigned(NQNFS_PROG);
- nqnfs_vers = txdr_unsigned(NQNFS_VER1);
/*
* If an authorization string is being passed in, get it.
*/
if ((flag & NFSSVC_GOTAUTH) &&
- (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) {
- if (nmp->nm_flag & NFSMNT_HASAUTH)
- panic("cld kerb");
- if ((flag & NFSSVC_AUTHINFAIL) == 0) {
- if (ncd->ncd_authlen <= RPCAUTH_MAXSIZ &&
- copyin(ncd->ncd_authstr, nmp->nm_authstr,
- ncd->ncd_authlen) == 0) {
- nmp->nm_authtype = ncd->ncd_authtype;
- nmp->nm_authlen = ncd->ncd_authlen;
- } else
- nmp->nm_flag |= NFSMNT_AUTHERR;
+ (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) {
+ if (nmp->nm_flag & NFSMNT_HASAUTH)
+ panic("cld kerb");
+ if ((flag & NFSSVC_AUTHINFAIL) == 0) {
+ if (ncd->ncd_authlen <= nmp->nm_authlen &&
+ ncd->ncd_verflen <= nmp->nm_verflen &&
+ !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&&
+ !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){
+ nmp->nm_authtype = ncd->ncd_authtype;
+ nmp->nm_authlen = ncd->ncd_authlen;
+ nmp->nm_verflen = ncd->ncd_verflen;
+#ifdef NFSKERB
+ nmp->nm_key = ncd->ncd_key;
+#endif
} else
- nmp->nm_flag |= NFSMNT_AUTHERR;
- nmp->nm_flag |= NFSMNT_HASAUTH;
- wakeup((caddr_t)&nmp->nm_authlen);
+ nmp->nm_flag |= NFSMNT_AUTHERR;
+ } else
+ nmp->nm_flag |= NFSMNT_AUTHERR;
+ nmp->nm_flag |= NFSMNT_HASAUTH;
+ wakeup((caddr_t)&nmp->nm_authlen);
} else
- nmp->nm_flag |= NFSMNT_WAITAUTH;
+ nmp->nm_flag |= NFSMNT_WAITAUTH;
/*
* Loop every second updating queue until there is a termination sig.
@@ -1016,13 +1065,11 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
while (np != (void *)&nmp->nm_timerhead &&
(nmp->nm_flag & NFSMNT_DISMINPROG) == 0) {
vp = NFSTOV(np);
-if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash2");
vpid = vp->v_id;
if (np->n_expiry < time.tv_sec) {
if (vget(vp, 1) == 0) {
nmp->nm_inprog = vp;
if (vpid == vp->v_id) {
-if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3");
CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
np->n_timer.cqe_next = 0;
if ((np->n_flag & (NMODIFIED | NQNFSEVICTED))
@@ -1047,9 +1094,8 @@ if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3");
== NQNFSWRITE && vp->v_dirtyblkhd.lh_first &&
vget(vp, 1) == 0) {
nmp->nm_inprog = vp;
-if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4");
if (vpid == vp->v_id &&
- nqnfs_getlease(vp, NQL_WRITE, cred, p)==0)
+ nqnfs_getlease(vp, ND_WRITE, cred, p)==0)
np->n_brev = np->n_lrev;
vrele(vp);
nmp->nm_inprog = NULLVP;
@@ -1084,6 +1130,16 @@ if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4");
(void) dounmount(nmp->nm_mountp, 0, p);
}
}
+
+ /*
+ * Finally, we can free up the mount structure.
+ */
+ for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) {
+ nnuidp = nuidp->nu_lru.tqe_next;
+ LIST_REMOVE(nuidp, nu_hash);
+ TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
+ free((caddr_t)nuidp, M_NFSUID);
+ }
free((caddr_t)nmp, M_NFSMNT);
if (error == EWOULDBLOCK)
error = 0;
@@ -1095,7 +1151,7 @@ if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4");
* Called from the settimeofday() syscall.
*/
void
-nfs_lease_updatetime(deltat)
+nqnfs_lease_updatetime(deltat)
register int deltat;
{
register struct nqlease *lp;
@@ -1116,8 +1172,17 @@ nfs_lease_updatetime(deltat)
* Search the mount list for all nqnfs mounts and do their timer
* queues.
*/
+#if NetBSD >= 1994101
+ for (mp = mountlist.cqh_first; mp != (void *)&mountlist;
+ mp = mp->mnt_list.cqe_next) {
+#else
for (mp = mountlist.tqh_first; mp != NULL; mp = mp->mnt_list.tqe_next) {
+#endif
+#ifdef __NetBSD__
+ if (!strcmp(&mp->mnt_stat.f_fstypename[0], MOUNT_NFS)) {
+#else
if (mp->mnt_stat.f_fsid.val[1] == MOUNT_NFS) {
+#endif
nmp = VFSTONFS(mp);
if (nmp->nm_flag & NFSMNT_NQNFS) {
for (np = nmp->nm_timerhead.cqh_first;
@@ -1174,9 +1239,9 @@ nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
if (np->n_timer.cqe_next != 0) {
CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
- if (rwflag == NQL_WRITE)
+ if (rwflag == ND_WRITE)
np->n_flag |= NQNFSWRITE;
- } else if (rwflag == NQL_READ)
+ } else if (rwflag == ND_READ)
np->n_flag &= ~NQNFSWRITE;
else
np->n_flag |= NQNFSWRITE;
diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c
index 033dae4c8741..f82db3b1d8a3 100644
--- a/sys/nfs/nfs_serv.c
+++ b/sys/nfs/nfs_serv.c
@@ -34,11 +34,11 @@
* SUCH DAMAGE.
*
* @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94
- * $Id: nfs_serv.c,v 1.14.2.1 1995/06/07 07:25:09 davidg Exp $
+ * $Id: nfs_serv.c,v 1.15 1995/06/11 19:31:45 rgrimes Exp $
*/
/*
- * nfs version 2 server calls to vnode ops
+ * nfs version 2 and 3 server calls to vnode ops
* - these routines generally have 3 phases
* 1 - break down and validate rpc request in mbuf list
* 2 - do the vnode ops for the request
@@ -53,6 +53,8 @@
* returning an error from the server function implies a fatal error
* such as a badly constructed rpc request that should be dropped without
* a reply.
+ * For Version 3, nfsm_reply() does not return for the error case, since
+ * most version 3 rpcs return more than the status for error cases.
*/
#include <sys/param.h>
@@ -62,67 +64,98 @@
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
#include <sys/mbuf.h>
#include <sys/dirent.h>
#include <sys/stat.h>
+#include <sys/kernel.h>
+#include <ufs/ufs/dir.h>
#include <vm/vm.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/rpcv2.h>
#include <nfs/nfs.h>
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/nqnfs.h>
-/* Defs */
-#define TRUE 1
-#define FALSE 0
-
/* Global vars */
-extern u_long nfs_procids[NFS_NPROCS];
extern u_long nfs_xdrneg1;
extern u_long nfs_false, nfs_true;
-nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
+extern enum vtype nv3tov_type[8];
+extern struct nfsstats nfsstats;
+nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
NFCHR, NFNON };
+nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
+ NFFIFO, NFNON };
+int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
/*
- * nqnfs access service
+ * nfs v3 access service
*/
int
-nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv3_access(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
struct vnode *vp;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, rdonly, cache = 0, mode = 0;
+ int error = 0, rdonly, cache, getret;
char *cp2;
- struct mbuf *mb, *mreq;
+ struct mbuf *mb, *mreq, *mb2;
+ struct vattr vattr, *vap = &vattr;
+ u_long testmode, nfsmode;
u_quad_t frev;
+#ifndef nolint
+ cache = 0;
+#endif
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
- if (*tl++ == nfs_true)
- mode |= VREAD;
- if (*tl++ == nfs_true)
- mode |= VWRITE;
- if (*tl == nfs_true)
- mode |= VEXEC;
- error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp);
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(1, (struct vattr *)0);
+ return (0);
+ }
+ nfsmode = fxdr_unsigned(u_long, *tl);
+ if ((nfsmode & NFSV3ACCESS_READ) &&
+ nfsrv_access(vp, VREAD, cred, rdonly, procp))
+ nfsmode &= ~NFSV3ACCESS_READ;
+ if (vp->v_type == VDIR)
+ testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
+ NFSV3ACCESS_DELETE);
+ else
+ testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
+ if ((nfsmode & testmode) &&
+ nfsrv_access(vp, VWRITE, cred, rdonly, procp))
+ nfsmode &= ~testmode;
+ if (vp->v_type == VDIR)
+ testmode = NFSV3ACCESS_LOOKUP;
+ else
+ testmode = NFSV3ACCESS_EXECUTE;
+ if ((nfsmode & testmode) &&
+ nfsrv_access(vp, VEXEC, cred, rdonly, procp))
+ nfsmode &= ~testmode;
+ getret = VOP_GETATTR(vp, vap, cred, procp);
nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, vap);
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(nfsmode);
nfsm_srvdone;
}
@@ -130,18 +163,21 @@ nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq)
* nfs getattr service
*/
int
-nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_getattr(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
- register struct nfsv2_fattr *fp;
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register struct nfs_fattr *fp;
struct vattr va;
register struct vattr *vap = &va;
struct vnode *vp;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
register u_long *tl;
register long t1;
@@ -153,15 +189,19 @@ nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
nfsm_reply(0);
- nqsrv_getl(vp, NQL_READ);
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
+ return (0);
+ }
+ nqsrv_getl(vp, ND_READ);
+ error = VOP_GETATTR(vp, vap, cred, procp);
nfsrv_vput(vp);
- nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfillattr;
+ nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
+ if (error)
+ return (0);
+ nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
+ nfsm_srvfillattr(vap, fp);
nfsm_srvdone;
}
@@ -169,68 +209,97 @@ nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
* nfs setattr service
*/
int
-nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_setattr(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
- struct vattr va;
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ struct vattr va, preat;
register struct vattr *vap = &va;
register struct nfsv2_sattr *sp;
- register struct nfsv2_fattr *fp;
+ register struct nfs_fattr *fp;
struct vnode *vp;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, rdonly, cache;
+ int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
char *cp2;
struct mbuf *mb, *mb2, *mreq;
- u_quad_t frev, frev2;
+ u_quad_t frev;
+ struct timespec guard;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
- nqsrv_getl(vp, NQL_WRITE);
VATTR_NULL(vap);
- /*
- * Nah nah nah nah na nah
- * There is a bug in the Sun client that puts 0xffff in the mode
- * field of sattr when it should put in 0xffffffff. The u_short
- * doesn't sign extend.
- * --> check the low order 2 bytes for 0xffff
- */
- if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
- vap->va_mode = nfstov_mode(sp->sa_mode);
- if (sp->sa_uid != nfs_xdrneg1)
- vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
- if (sp->sa_gid != nfs_xdrneg1)
- vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
- if (nfsd->nd_nqlflag == NQL_NOVAL) {
- if (sp->sa_nfssize != nfs_xdrneg1)
- vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize);
- if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) {
+ if (v3) {
+ nfsm_srvsattr(vap);
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ gcheck = fxdr_unsigned(int, *tl);
+ if (gcheck) {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ fxdr_nfsv3time(tl, &guard);
+ }
+ } else {
+ nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ /*
+ * Nah nah nah nah na nah
+ * There is a bug in the Sun client that puts 0xffff in the mode
+ * field of sattr when it should put in 0xffffffff. The u_short
+ * doesn't sign extend.
+ * --> check the low order 2 bytes for 0xffff
+ */
+ if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
+ vap->va_mode = nfstov_mode(sp->sa_mode);
+ if (sp->sa_uid != nfs_xdrneg1)
+ vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
+ if (sp->sa_gid != nfs_xdrneg1)
+ vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
+ if (sp->sa_size != nfs_xdrneg1)
+ vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
+ if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
#ifdef notyet
- fxdr_nfstime(&sp->sa_nfsatime, &vap->va_atime);
+ fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
#else
vap->va_atime.ts_sec =
- fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec);
+ fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
vap->va_atime.ts_nsec = 0;
#endif
}
- if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1)
- fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime);
- } else {
- fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
- fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime);
- fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime);
- vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags);
+ if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
+ fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
+
+ }
+
+ /*
+ * Now that we have all the fields, lets do it.
+ */
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(2 * NFSX_UNSIGNED);
+ nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
+ return (0);
+ }
+ nqsrv_getl(vp, ND_WRITE);
+ if (v3) {
+ error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
+ if (!error && gcheck &&
+ (preat.va_ctime.ts_sec != guard.ts_sec ||
+ preat.va_ctime.ts_nsec != guard.ts_nsec))
+ error = NFSERR_NOT_SYNC;
+ if (error) {
+ nfsrv_vput(vp);
+ nfsm_reply(NFSX_WCCDATA(v3));
+ nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
+ return (0);
+ }
}
/*
@@ -246,27 +315,23 @@ nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
if (vp->v_type == VDIR) {
error = EISDIR;
goto out;
- } else {
- error = nfsrv_access(vp, VWRITE, cred, rdonly,
- nfsd->nd_procp);
- if (error)
- goto out;
- }
- }
- error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp);
- if (error) {
- nfsrv_vput(vp);
- nfsm_reply(0);
+ } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
+ procp))
+ goto out;
}
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
+ error = VOP_SETATTR(vp, vap, cred, procp);
+ postat_ret = VOP_GETATTR(vp, vap, cred, procp);
+ if (!error)
+ error = postat_ret;
out:
nfsrv_vput(vp);
- nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED);
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfillattr;
- if (nfsd->nd_nqlflag != NQL_NOVAL) {
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- txdr_hyper(&frev2, tl);
+ nfsm_reply(NFSX_WCCORFATTR(v3));
+ if (v3) {
+ nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
+ return (0);
+ } else {
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
+ nfsm_srvfillattr(vap, fp);
}
nfsm_srvdone;
}
@@ -275,76 +340,74 @@ out:
* nfs lookup rpc
*/
int
-nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_lookup(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
- register struct nfsv2_fattr *fp;
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register struct nfs_fattr *fp;
struct nameidata nd;
- struct vnode *vp;
- nfsv2fh_t nfh;
+ struct vnode *vp, *dirp;
+ nfsfh_t nfh;
fhandle_t *fhp;
register caddr_t cp;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, cache, cache2, len;
- u_long duration2;
+ int error = 0, cache, len, dirattr_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
struct mbuf *mb, *mb2, *mreq;
- struct vattr va, *vap = &va;
- u_quad_t frev, frev2;
+ struct vattr va, dirattr, *vap = &va;
+ u_quad_t frev;
fhp = &nfh.fh_generic;
- duration2 = 0;
- if (nfsd->nd_nqlflag != NQL_NOVAL) {
- nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
- duration2 = fxdr_unsigned(int, *tl);
- }
nfsm_srvmtofh(fhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = LOOKUP;
nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
- error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
- if (error)
- nfsm_reply(0);
- nqsrv_getl(nd.ni_startdir, NQL_READ);
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
+ procp);
+ nfsrv_vrele(dirp);
+ }
+ if (error) {
+ nfsm_reply(NFSX_POSTOPATTR(v3));
+ nfsm_srvpostop_attr(dirattr_ret, &dirattr);
+ return (0);
+ }
+ nqsrv_getl(nd.ni_startdir, ND_READ);
nfsrv_vrele(nd.ni_startdir);
FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
vp = nd.ni_vp;
bzero((caddr_t)fhp, sizeof(nfh));
fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
error = VFS_VPTOFH(vp, &fhp->fh_fid);
+ if (!error)
+ error = VOP_GETATTR(vp, vap, cred, procp);
+ nfsrv_vput(vp);
+ nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
if (error) {
- nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_srvpostop_attr(dirattr_ret, &dirattr);
+ return (0);
}
- if (duration2)
- (void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd,
- nam, &cache2, &frev2, cred);
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
- nfsrv_vput(vp);
- nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED);
- if (nfsd->nd_nqlflag != NQL_NOVAL) {
- if (duration2) {
- nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(NQL_READ);
- *tl++ = txdr_unsigned(cache2);
- *tl++ = txdr_unsigned(duration2);
- txdr_hyper(&frev2, tl);
- } else {
- nfsm_build(tl, u_long *, NFSX_UNSIGNED);
- *tl = 0;
- }
+ nfsm_srvfhtom(fhp, v3);
+ if (v3) {
+ nfsm_srvpostop_attr(0, vap);
+ nfsm_srvpostop_attr(dirattr_ret, &dirattr);
+ } else {
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
+ nfsm_srvfillattr(vap, fp);
}
- nfsm_srvfhtom(fhp);
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfillattr;
nfsm_srvdone;
}
@@ -352,28 +415,36 @@ nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
* nfs readlink service
*/
int
-nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_readlink(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
register struct iovec *ivp = iv;
register struct mbuf *mp;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, rdonly, cache, i, tlen, len;
+ int error = 0, rdonly, cache, i, tlen, len, getret;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
- struct mbuf *mb, *mb2, *mp2 = 0, *mp3 = 0, *mreq;
+ struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
struct vnode *vp;
- nfsv2fh_t nfh;
+ struct vattr attr;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct uio io, *uiop = &io;
u_quad_t frev;
+#ifndef nolint
+ mp2 = mp3 = (struct mbuf *)0;
+#endif
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
len = 0;
@@ -405,22 +476,33 @@ nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
uiop->uio_rw = UIO_READ;
uiop->uio_segflg = UIO_SYSSPACE;
uiop->uio_procp = (struct proc *)0;
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error) {
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
m_freem(mp3);
- nfsm_reply(0);
+ nfsm_reply(2 * NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(1, (struct vattr *)0);
+ return (0);
}
if (vp->v_type != VLNK) {
- error = EINVAL;
+ if (v3)
+ error = EINVAL;
+ else
+ error = ENXIO;
goto out;
}
- nqsrv_getl(vp, NQL_READ);
+ nqsrv_getl(vp, ND_READ);
error = VOP_READLINK(vp, uiop, cred);
out:
+ getret = VOP_GETATTR(vp, &attr, cred, procp);
nfsrv_vput(vp);
if (error)
m_freem(mp3);
- nfsm_reply(NFSX_UNSIGNED);
+ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
+ if (v3) {
+ nfsm_srvpostop_attr(getret, &attr);
+ if (error)
+ return (0);
+ }
if (uiop->uio_resid > 0) {
len -= uiop->uio_resid;
tlen = nfsm_rndup(len);
@@ -436,26 +518,31 @@ out:
* nfs read service
*/
int
-nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_read(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register struct iovec *iv;
struct iovec *iv2;
register struct mbuf *m;
- register struct nfsv2_fattr *fp;
+ register struct nfs_fattr *fp;
register u_long *tl;
register long t1;
+ register int i;
caddr_t bpos;
- int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen;
+ int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
+ int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
char *cp2;
struct mbuf *mb, *mb2, *mreq;
struct mbuf *m2;
struct vnode *vp;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct uio io, *uiop = &io;
struct vattr va, *vap = &va;
@@ -464,40 +551,57 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- if (nfsd->nd_nqlflag == NQL_NOVAL) {
- nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
- off = (off_t)fxdr_unsigned(u_long, *tl);
- } else {
+ if (v3) {
nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
fxdr_hyper(tl, &off);
+ } else {
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ off = (off_t)fxdr_unsigned(u_long, *tl);
+ }
+ nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(2 * NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(1, (struct vattr *)0);
+ return (0);
}
- nfsm_srvstrsiz(cnt, NFS_MAXDATA);
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
if (vp->v_type != VREG) {
- error = (vp->v_type == VDIR) ? EISDIR : EACCES;
- nfsrv_vput(vp);
- nfsm_reply(0);
+ if (v3)
+ error = EINVAL;
+ else
+ error = (vp->v_type == VDIR) ? EISDIR : EACCES;
}
- nqsrv_getl(vp, NQL_READ);
- if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) &&
- (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) {
- nfsrv_vput(vp);
- nfsm_reply(0);
+ if (!error) {
+ nqsrv_getl(vp, ND_READ);
+ if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
+ error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
}
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
+ getret = VOP_GETATTR(vp, vap, cred, procp);
+ if (!error)
+ error = getret;
if (error) {
nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_POSTOPATTR(v3));
+ nfsm_srvpostop_attr(getret, vap);
+ return (0);
}
if (off >= vap->va_size)
cnt = 0;
- else if ((off + cnt) > vap->va_size)
+ else if ((off + reqlen) > vap->va_size)
cnt = nfsm_rndup(vap->va_size - off);
- nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt));
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ else
+ cnt = reqlen;
+ nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
+ if (v3) {
+ nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ fp = (struct nfs_fattr *)tl;
+ tl += (NFSX_V3FATTR / sizeof (u_long));
+ } else {
+ nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
+ fp = (struct nfs_fattr *)tl;
+ tl += (NFSX_V2FATTR / sizeof (u_long));
+ }
len = left = cnt;
if (cnt > 0) {
/*
@@ -505,19 +609,11 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
*/
i = 0;
m = m2 = mb;
- MALLOC(iv, struct iovec *,
- ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec),
- M_TEMP, M_WAITOK);
- iv2 = iv;
while (left > 0) {
siz = min(M_TRAILINGSPACE(m), left);
if (siz > 0) {
- m->m_len += siz;
- iv->iov_base = bpos;
- iv->iov_len = siz;
- iv++;
- i++;
left -= siz;
+ i++;
}
if (left > 0) {
MGET(m, M_WAIT, MT_DATA);
@@ -525,10 +621,28 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
m->m_len = 0;
m2->m_next = m;
m2 = m;
- bpos = mtod(m, caddr_t);
}
}
- uiop->uio_iov = iv2;
+ MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
+ M_TEMP, M_WAITOK);
+ uiop->uio_iov = iv2 = iv;
+ m = mb;
+ left = cnt;
+ i = 0;
+ while (left > 0) {
+ if (m == NULL)
+ panic("nfsrv_read iov");
+ siz = min(M_TRAILINGSPACE(m), left);
+ if (siz > 0) {
+ iv->iov_base = mtod(m, caddr_t) + m->m_len;
+ iv->iov_len = siz;
+ m->m_len += siz;
+ left -= siz;
+ iv++;
+ i++;
+ }
+ m = m->m_next;
+ }
uiop->uio_iovcnt = i;
uiop->uio_offset = off;
uiop->uio_resid = cnt;
@@ -537,19 +651,30 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
off = uiop->uio_offset;
FREE((caddr_t)iv2, M_TEMP);
- if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) {
+ if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
+ if (!error)
+ error = getret;
m_freem(mreq);
nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_POSTOPATTR(v3));
+ nfsm_srvpostop_attr(getret, vap);
+ return (0);
}
} else
uiop->uio_resid = 0;
nfsrv_vput(vp);
- nfsm_srvfillattr;
+ nfsm_srvfillattr(vap, fp);
len -= uiop->uio_resid;
tlen = nfsm_rndup(len);
if (cnt != tlen || tlen != len)
- nfsm_adj(mb, cnt-tlen, tlen-len);
+ nfsm_adj(mb, cnt - tlen, tlen - len);
+ if (v3) {
+ *tl++ = txdr_unsigned(len);
+ if (len < reqlen)
+ *tl++ = nfs_true;
+ else
+ *tl++ = nfs_false;
+ }
*tl = txdr_unsigned(len);
nfsm_srvdone;
}
@@ -558,132 +683,580 @@ nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
* nfs write service
*/
int
-nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_write(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register struct iovec *ivp;
+ register int i, cnt;
register struct mbuf *mp;
- register struct nfsv2_fattr *fp;
- struct iovec iv[NFS_MAXIOVEC];
- struct vattr va;
+ register struct nfs_fattr *fp;
+ struct iovec *iv;
+ struct vattr va, forat;
register struct vattr *vap = &va;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, rdonly, cache, siz, len, xfer;
- int ioflags = IO_SYNC | IO_NODELOCKED;
+ int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1;
+ int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
+ int stable = NFSV3WRITE_FILESYNC;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
struct mbuf *mb, *mb2, *mreq;
struct vnode *vp;
- nfsv2fh_t nfh;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct uio io, *uiop = &io;
off_t off;
u_quad_t frev;
+ if (mrep == NULL) {
+ *mrq = NULL;
+ return (0);
+ }
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
- if (nfsd->nd_nqlflag == NQL_NOVAL) {
- off = (off_t)fxdr_unsigned(u_long, *++tl);
- tl += 2;
- } else {
+ if (v3) {
+ nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
fxdr_hyper(tl, &off);
+ tl += 3;
+ stable = fxdr_unsigned(int, *tl++);
+ } else {
+ nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
+ off = (off_t)fxdr_unsigned(u_long, *++tl);
tl += 2;
- if (fxdr_unsigned(u_long, *tl++))
- ioflags |= IO_APPEND;
}
- len = fxdr_unsigned(long, *tl);
- if (len > NFS_MAXDATA || len <= 0) {
- error = EBADRPC;
- nfsm_reply(0);
- }
- if (dpos == (mtod(md, caddr_t)+md->m_len)) {
- mp = md->m_next;
- if (mp == NULL) {
- error = EBADRPC;
- nfsm_reply(0);
+ retlen = len = fxdr_unsigned(long, *tl);
+ cnt = i = 0;
+
+ /*
+ * For NFS Version 2, it is not obvious what a write of zero length
+ * should do, but I might as well be consistent with Version 3,
+ * which is to return ok so long as there are no permission problems.
+ */
+ if (len > 0) {
+ zeroing = 1;
+ mp = mrep;
+ while (mp) {
+ if (mp == md) {
+ zeroing = 0;
+ adjust = dpos - mtod(mp, caddr_t);
+ mp->m_len -= adjust;
+ if (mp->m_len > 0 && adjust > 0)
+ NFSMADV(mp, adjust);
}
- } else {
- mp = md;
- siz = dpos-mtod(mp, caddr_t);
- mp->m_len -= siz;
- NFSMADV(mp, siz);
+ if (zeroing)
+ mp->m_len = 0;
+ else if (mp->m_len > 0) {
+ i += mp->m_len;
+ if (i > len) {
+ mp->m_len -= (i - len);
+ zeroing = 1;
+ }
+ if (mp->m_len > 0)
+ cnt++;
+ }
+ mp = mp->m_next;
+ }
}
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
+ if (len > NFS_MAXDATA || len < 0 || i < len) {
+ error = EIO;
+ nfsm_reply(2 * NFSX_UNSIGNED);
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
+ return (0);
+ }
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(2 * NFSX_UNSIGNED);
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
+ return (0);
+ }
+ if (v3)
+ forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
if (vp->v_type != VREG) {
- error = (vp->v_type == VDIR) ? EISDIR : EACCES;
- nfsrv_vput(vp);
- nfsm_reply(0);
+ if (v3)
+ error = EINVAL;
+ else
+ error = (vp->v_type == VDIR) ? EISDIR : EACCES;
+ }
+ if (!error) {
+ nqsrv_getl(vp, ND_WRITE);
+ error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
}
- nqsrv_getl(vp, NQL_WRITE);
- error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp);
if (error) {
nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_WCCDATA(v3));
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
+ return (0);
}
- uiop->uio_resid = 0;
- uiop->uio_rw = UIO_WRITE;
- uiop->uio_segflg = UIO_SYSSPACE;
- uiop->uio_procp = (struct proc *)0;
+
+ if (len > 0) {
+ MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
+ M_WAITOK);
+ uiop->uio_iov = iv = ivp;
+ uiop->uio_iovcnt = cnt;
+ mp = mrep;
+ while (mp) {
+ if (mp->m_len > 0) {
+ ivp->iov_base = mtod(mp, caddr_t);
+ ivp->iov_len = mp->m_len;
+ ivp++;
+ }
+ mp = mp->m_next;
+ }
+
+ /*
+ * XXX
+ * The IO_METASYNC flag indicates that all metadata (and not just
+ * enough to ensure data integrity) mus be written to stable storage
+ * synchronously.
+ * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
+ */
+ if (stable == NFSV3WRITE_UNSTABLE)
+ ioflags = IO_NODELOCKED;
+ else if (stable == NFSV3WRITE_DATASYNC)
+ ioflags = (IO_SYNC | IO_NODELOCKED);
+ else
+ ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
+ uiop->uio_resid = len;
+ uiop->uio_rw = UIO_WRITE;
+ uiop->uio_segflg = UIO_SYSSPACE;
+ uiop->uio_procp = (struct proc *)0;
+ uiop->uio_offset = off;
+ error = VOP_WRITE(vp, uiop, ioflags, cred);
+ nfsstats.srvvop_writes++;
+ FREE((caddr_t)iv, M_TEMP);
+ }
+ aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
+ nfsrv_vput(vp);
+ if (!error)
+ error = aftat_ret;
+ nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
+ 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
+ if (v3) {
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
+ if (error)
+ return (0);
+ nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
+ *tl++ = txdr_unsigned(retlen);
+ if (stable == NFSV3WRITE_UNSTABLE)
+ *tl++ = txdr_unsigned(stable);
+ else
+ *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
+ /*
+ * Actually, there is no need to txdr these fields,
+ * but it may make the values more human readable,
+ * for debugging purposes.
+ */
+ *tl++ = txdr_unsigned(boottime.tv_sec);
+ *tl = txdr_unsigned(boottime.tv_usec);
+ } else {
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
+ nfsm_srvfillattr(vap, fp);
+ }
+ nfsm_srvdone;
+}
+
+/*
+ * NFS write service with write gathering support. Called when
+ * nfsrvw_procrastinate > 0.
+ * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
+ * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
+ * Jan. 1994.
+ */
+int
+nfsrv_writegather(ndp, slp, procp, mrq)
+ struct nfsrv_descript **ndp;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
+{
+ register struct iovec *ivp;
+ register struct mbuf *mp;
+ register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
+ register struct nfs_fattr *fp;
+ register int i;
+ struct iovec *iov;
+ struct nfsrvw_delayhash *wpp;
+ struct ucred *cred;
+ struct vattr va, forat;
+ register u_long *tl;
+ register long t1;
+ caddr_t bpos, dpos;
+ int error = 0, rdonly, cache, len, forat_ret = 1;
+ int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
+ char *cp2;
+ struct mbuf *mb, *mb2, *mreq, *mrep, *md;
+ struct vnode *vp;
+ struct uio io, *uiop = &io;
+ off_t off;
+ u_quad_t frev, cur_usec;
+
+#ifndef nolint
+ i = 0;
+ len = 0;
+#endif
+ *mrq = NULL;
+ if (*ndp) {
+ nfsd = *ndp;
+ *ndp = NULL;
+ mrep = nfsd->nd_mrep;
+ md = nfsd->nd_md;
+ dpos = nfsd->nd_dpos;
+ cred = &nfsd->nd_cr;
+ v3 = (nfsd->nd_flag & ND_NFSV3);
+ LIST_INIT(&nfsd->nd_coalesce);
+ nfsd->nd_mreq = NULL;
+ nfsd->nd_stable = NFSV3WRITE_FILESYNC;
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
+ nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
+
+ /*
+ * Now, get the write header..
+ */
+ nfsm_srvmtofh(&nfsd->nd_fh);
+ if (v3) {
+ nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
+ fxdr_hyper(tl, &nfsd->nd_off);
+ tl += 3;
+ nfsd->nd_stable = fxdr_unsigned(int, *tl++);
+ } else {
+ nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
+ nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
+ tl += 2;
+ }
+ len = fxdr_unsigned(long, *tl);
+ nfsd->nd_len = len;
+ nfsd->nd_eoff = nfsd->nd_off + len;
+
+ /*
+ * Trim the header out of the mbuf list and trim off any trailing
+ * junk so that the mbuf list has only the write data.
+ */
+ zeroing = 1;
+ i = 0;
+ mp = mrep;
+ while (mp) {
+ if (mp == md) {
+ zeroing = 0;
+ adjust = dpos - mtod(mp, caddr_t);
+ mp->m_len -= adjust;
+ if (mp->m_len > 0 && adjust > 0)
+ NFSMADV(mp, adjust);
+ }
+ if (zeroing)
+ mp->m_len = 0;
+ else {
+ i += mp->m_len;
+ if (i > len) {
+ mp->m_len -= (i - len);
+ zeroing = 1;
+ }
+ }
+ mp = mp->m_next;
+ }
+ if (len > NFS_MAXDATA || len < 0 || i < len) {
+nfsmout:
+ m_freem(mrep);
+ error = EIO;
+ nfsm_writereply(2 * NFSX_UNSIGNED, v3);
+ if (v3)
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
+ nfsd->nd_mreq = mreq;
+ nfsd->nd_mrep = NULL;
+ nfsd->nd_time = 0;
+ }
+
+ /*
+ * Add this entry to the hash and time queues.
+ */
+ s = splsoftclock();
+ owp = NULL;
+ wp = slp->ns_tq.lh_first;
+ while (wp && wp->nd_time < nfsd->nd_time) {
+ owp = wp;
+ wp = wp->nd_tq.le_next;
+ }
+ if (owp) {
+ LIST_INSERT_AFTER(owp, nfsd, nd_tq);
+ } else {
+ LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
+ }
+ if (nfsd->nd_mrep) {
+ wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
+ owp = NULL;
+ wp = wpp->lh_first;
+ while (wp &&
+ bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
+ owp = wp;
+ wp = wp->nd_hash.le_next;
+ }
+ while (wp && wp->nd_off < nfsd->nd_off &&
+ !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
+ owp = wp;
+ wp = wp->nd_hash.le_next;
+ }
+ if (owp) {
+ LIST_INSERT_AFTER(owp, nfsd, nd_hash);
+
+ /*
+ * Search the hash list for overlapping entries and
+ * coalesce.
+ */
+ for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
+ wp = nfsd->nd_hash.le_next;
+ if (NFSW_SAMECRED(owp, nfsd))
+ nfsrvw_coalesce(owp, nfsd);
+ }
+ } else {
+ LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
+ }
+ }
+ splx(s);
+ }
+
/*
- * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
- * loop until done.
+ * Now, do VOP_WRITE()s for any one(s) that need to be done now
+ * and generate the associated reply mbuf list(s).
*/
- while (len > 0 && uiop->uio_resid == 0) {
- ivp = iv;
- siz = 0;
- uiop->uio_iov = ivp;
- uiop->uio_iovcnt = 0;
- uiop->uio_offset = off;
- while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
- ivp->iov_base = mtod(mp, caddr_t);
- if (len < mp->m_len)
- ivp->iov_len = xfer = len;
+loop1:
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
+ s = splsoftclock();
+ for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
+ owp = nfsd->nd_tq.le_next;
+ if (nfsd->nd_time > cur_usec)
+ break;
+ if (nfsd->nd_mreq)
+ continue;
+ LIST_REMOVE(nfsd, nd_tq);
+ LIST_REMOVE(nfsd, nd_hash);
+ splx(s);
+ mrep = nfsd->nd_mrep;
+ nfsd->nd_mrep = NULL;
+ cred = &nfsd->nd_cr;
+ v3 = (nfsd->nd_flag & ND_NFSV3);
+ forat_ret = aftat_ret = 1;
+ error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
+ nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
+ if (!error) {
+ if (v3)
+ forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
+ if (vp->v_type != VREG) {
+ if (v3)
+ error = EINVAL;
else
- ivp->iov_len = xfer = mp->m_len;
-#ifdef notdef
- /* Not Yet .. */
- if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
- ivp->iov_op = NULL; /* what should it be ?? */
- else
- ivp->iov_op = NULL;
-#endif
- uiop->uio_iovcnt++;
- ivp++;
- len -= xfer;
- siz += xfer;
+ error = (vp->v_type == VDIR) ? EISDIR : EACCES;
+ }
+ } else
+ vp = NULL;
+ if (!error) {
+ nqsrv_getl(vp, ND_WRITE);
+ error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
+ }
+
+ if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
+ ioflags = IO_NODELOCKED;
+ else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
+ ioflags = (IO_SYNC | IO_NODELOCKED);
+ else
+ ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
+ uiop->uio_rw = UIO_WRITE;
+ uiop->uio_segflg = UIO_SYSSPACE;
+ uiop->uio_procp = (struct proc *)0;
+ uiop->uio_offset = nfsd->nd_off;
+ uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
+ if (uiop->uio_resid > 0) {
+ mp = mrep;
+ i = 0;
+ while (mp) {
+ if (mp->m_len > 0)
+ i++;
+ mp = mp->m_next;
+ }
+ uiop->uio_iovcnt = i;
+ MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
+ M_TEMP, M_WAITOK);
+ uiop->uio_iov = ivp = iov;
+ mp = mrep;
+ while (mp) {
+ if (mp->m_len > 0) {
+ ivp->iov_base = mtod(mp, caddr_t);
+ ivp->iov_len = mp->m_len;
+ ivp++;
+ }
mp = mp->m_next;
+ }
+ if (!error) {
+ error = VOP_WRITE(vp, uiop, ioflags, cred);
+ nfsstats.srvvop_writes++;
+ }
+ FREE((caddr_t)iov, M_TEMP);
}
- if (len > 0 && mp == NULL) {
- error = EBADRPC;
- nfsrv_vput(vp);
- nfsm_reply(0);
+ m_freem(mrep);
+ if (vp) {
+ aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
+ nfsrv_vput(vp);
}
- uiop->uio_resid = siz;
- error = VOP_WRITE(vp, uiop, ioflags, cred);
- if (error) {
- nfsrv_vput(vp);
- nfsm_reply(0);
- }
- off = uiop->uio_offset;
+
+ /*
+ * Loop around generating replies for all write rpcs that have
+ * now been completed.
+ */
+ swp = nfsd;
+ do {
+ if (error) {
+ nfsm_writereply(NFSX_WCCDATA(v3), v3);
+ if (v3) {
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
+ }
+ } else {
+ nfsm_writereply(NFSX_PREOPATTR(v3) +
+ NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
+ NFSX_WRITEVERF(v3), v3);
+ if (v3) {
+ nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
+ nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
+ *tl++ = txdr_unsigned(nfsd->nd_len);
+ *tl++ = txdr_unsigned(swp->nd_stable);
+ /*
+ * Actually, there is no need to txdr these fields,
+ * but it may make the values more human readable,
+ * for debugging purposes.
+ */
+ *tl++ = txdr_unsigned(boottime.tv_sec);
+ *tl = txdr_unsigned(boottime.tv_usec);
+ } else {
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
+ nfsm_srvfillattr(&va, fp);
+ }
+ }
+ nfsd->nd_mreq = mreq;
+ if (nfsd->nd_mrep)
+ panic("nfsrv_write: nd_mrep not free");
+
+ /*
+ * Done. Put it at the head of the timer queue so that
+ * the final phase can return the reply.
+ */
+ s = splsoftclock();
+ if (nfsd != swp) {
+ nfsd->nd_time = 0;
+ LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
+ }
+ nfsd = swp->nd_coalesce.lh_first;
+ if (nfsd) {
+ LIST_REMOVE(nfsd, nd_tq);
+ }
+ splx(s);
+ } while (nfsd);
+ s = splsoftclock();
+ swp->nd_time = 0;
+ LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
+ splx(s);
+ goto loop1;
}
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
- nfsrv_vput(vp);
- nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfillattr;
- if (nfsd->nd_nqlflag != NQL_NOVAL) {
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- txdr_hyper(&vap->va_filerev, tl);
+ splx(s);
+
+ /*
+ * Search for a reply to return.
+ */
+ s = splsoftclock();
+ for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
+ if (nfsd->nd_mreq) {
+ LIST_REMOVE(nfsd, nd_tq);
+ *mrq = nfsd->nd_mreq;
+ *ndp = nfsd;
+ break;
+ }
+ splx(s);
+ return (0);
+}
+
+/*
+ * Coalesce the write request nfsd into owp. To do this we must:
+ * - remove nfsd from the queues
+ * - merge nfsd->nd_mrep into owp->nd_mrep
+ * - update the nd_eoff and nd_stable for owp
+ * - put nfsd on owp's nd_coalesce list
+ * NB: Must be called at splsoftclock().
+ */
+void
+nfsrvw_coalesce(owp, nfsd)
+ register struct nfsrv_descript *owp;
+ register struct nfsrv_descript *nfsd;
+{
+ register int overlap;
+ register struct mbuf *mp;
+
+ LIST_REMOVE(nfsd, nd_hash);
+ LIST_REMOVE(nfsd, nd_tq);
+ if (owp->nd_eoff < nfsd->nd_eoff) {
+ overlap = owp->nd_eoff - nfsd->nd_off;
+ if (overlap < 0)
+ panic("nfsrv_coalesce: bad off");
+ if (overlap > 0)
+ m_adj(nfsd->nd_mrep, overlap);
+ mp = owp->nd_mrep;
+ while (mp->m_next)
+ mp = mp->m_next;
+ mp->m_next = nfsd->nd_mrep;
+ owp->nd_eoff = nfsd->nd_eoff;
+ } else
+ m_freem(nfsd->nd_mrep);
+ nfsd->nd_mrep = NULL;
+ if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
+ owp->nd_stable = NFSV3WRITE_FILESYNC;
+ else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
+ owp->nd_stable == NFSV3WRITE_UNSTABLE)
+ owp->nd_stable = NFSV3WRITE_DATASYNC;
+ LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
+}
+
+/*
+ * Sort the group list in increasing numerical order.
+ * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
+ * that used to be here.)
+ */
+void
+nfsrvw_sort(list, num)
+ register gid_t *list;
+ register int num;
+{
+ register int i, j;
+ gid_t v;
+
+ /* Insertion sort. */
+ for (i = 1; i < num; i++) {
+ v = list[i];
+ /* find correct slot for value v, moving others up */
+ for (j = i; --j >= 0 && v < list[j];)
+ list[j + 1] = list[j];
+ list[j + 1] = v;
}
- nfsm_srvdone;
+}
+
+/*
+ * copy credentials making sure that the result can be compared with bcmp().
+ */
+void
+nfsrv_setcred(incred, outcred)
+ register struct ucred *incred, *outcred;
+{
+ register int i;
+
+ bzero((caddr_t)outcred, sizeof (struct ucred));
+ outcred->cr_ref = 1;
+ outcred->cr_uid = incred->cr_uid;
+ outcred->cr_ngroups = incred->cr_ngroups;
+ for (i = 0; i < incred->cr_ngroups; i++)
+ outcred->cr_groups[i] = incred->cr_groups[i];
+ nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
}
/*
@@ -691,15 +1264,18 @@ nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
* now does a truncate to 0 length via. setattr if it already exists
*/
int
-nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_create(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
- register struct nfsv2_fattr *fp;
- struct vattr va;
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register struct nfs_fattr *fp;
+ struct vattr va, dirfor, diraft;
register struct vattr *vap = &va;
register struct nfsv2_sattr *sp;
register u_long *tl;
@@ -707,75 +1283,131 @@ nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
register caddr_t cp;
register long t1;
caddr_t bpos;
- int error = 0, rdev, cache, len, tsize;
+ int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
char *cp2;
struct mbuf *mb, *mb2, *mreq;
- struct vnode *vp;
- nfsv2fh_t nfh;
+ struct vnode *vp, *dirp = (struct vnode *)0;
+ nfsfh_t nfh;
fhandle_t *fhp;
- u_quad_t frev;
+ u_quad_t frev, tempsize;
+ u_char cverf[NFSX_V3CREATEVERF];
+#ifndef nolint
+ rdev = 0;
+#endif
nd.ni_cnd.cn_nameiop = 0;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
- error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
- if (error)
- nfsm_reply(0);
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(dirp);
+ dirp = (struct vnode *)0;
+ }
+ }
+ if (error) {
+ nfsm_reply(NFSX_WCCDATA(v3));
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ if (dirp)
+ nfsrv_vrele(dirp);
+ return (0);
+ }
VATTR_NULL(vap);
- nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
+ if (v3) {
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ how = fxdr_unsigned(int, *tl);
+ switch (how) {
+ case NFSV3CREATE_GUARDED:
+ if (nd.ni_vp) {
+ error = EEXIST;
+ break;
+ }
+ case NFSV3CREATE_UNCHECKED:
+ nfsm_srvsattr(vap);
+ break;
+ case NFSV3CREATE_EXCLUSIVE:
+ nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
+ bcopy(cp, cverf, NFSX_V3CREATEVERF);
+ exclusive_flag = 1;
+ if (nd.ni_vp == NULL)
+ vap->va_mode = 0;
+ break;
+ };
+ vap->va_type = VREG;
+ } else {
+ nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
+ if (vap->va_type == VNON)
+ vap->va_type = VREG;
+ vap->va_mode = nfstov_mode(sp->sa_mode);
+ switch (vap->va_type) {
+ case VREG:
+ tsize = fxdr_unsigned(long, sp->sa_size);
+ if (tsize != -1)
+ vap->va_size = (u_quad_t)tsize;
+ break;
+ case VCHR:
+ case VBLK:
+ case VFIFO:
+ rdev = fxdr_unsigned(long, sp->sa_size);
+ break;
+ };
+ }
+
/*
* Iff doesn't exist, create it
* otherwise just truncate to 0 length
* should I set the mode too ??
*/
if (nd.ni_vp == NULL) {
- vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
- if (vap->va_type == VNON)
- vap->va_type = VREG;
- vap->va_mode = nfstov_mode(sp->sa_mode);
- if (nfsd->nd_nqlflag == NQL_NOVAL)
- rdev = fxdr_unsigned(long, sp->sa_nfssize);
- else
- rdev = fxdr_unsigned(long, sp->sa_nqrdev);
if (vap->va_type == VREG || vap->va_type == VSOCK) {
nfsrv_vrele(nd.ni_startdir);
- nqsrv_getl(nd.ni_dvp, NQL_WRITE);
- error=VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
- if (error)
- nfsm_reply(0);
- nfsrv_vmio(nd.ni_vp);
- FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
+ error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
+ if (!error) {
+ nfsrv_vmio(nd.ni_vp);
+ FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ if (exclusive_flag) {
+ exclusive_flag = 0;
+ VATTR_NULL(vap);
+ bcopy(cverf, (caddr_t)&vap->va_atime,
+ NFSX_V3CREATEVERF);
+ error = VOP_SETATTR(nd.ni_vp, vap, cred,
+ procp);
+ }
+ }
} else if (vap->va_type == VCHR || vap->va_type == VBLK ||
vap->va_type == VFIFO) {
if (vap->va_type == VCHR && rdev == 0xffffffff)
vap->va_type = VFIFO;
- if (vap->va_type == VFIFO) {
- } else {
- error = suser(cred, (u_short *)0);
- if (error) {
- VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
- nfsrv_vput(nd.ni_dvp);
- goto out;
- } else
- vap->va_rdev = (dev_t)rdev;
- }
- nqsrv_getl(nd.ni_dvp, NQL_WRITE);
- error=VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
- if (error) {
+ if (error = suser(cred, (u_short *)0)) {
+ nfsrv_vrele(nd.ni_startdir);
+ free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ nfsrv_vput(nd.ni_dvp);
+ nfsm_reply(0);
+ return (error);
+ } else
+ vap->va_rdev = (dev_t)rdev;
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
+ if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
nfsrv_vrele(nd.ni_startdir);
nfsm_reply(0);
}
nd.ni_cnd.cn_nameiop = LOOKUP;
nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
- nd.ni_cnd.cn_proc = nfsd->nd_procp;
- nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred;
- error = lookup(&nd);
- if (error) {
+ nd.ni_cnd.cn_proc = procp;
+ nd.ni_cnd.cn_cred = cred;
+ if (error = lookup(&nd)) {
free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
nfsm_reply(0);
}
@@ -789,10 +1421,11 @@ nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
nfsm_reply(0);
}
} else {
+ nfsrv_vrele(nd.ni_startdir);
+ free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
nfsrv_vput(nd.ni_dvp);
error = ENXIO;
- goto out;
}
vp = nd.ni_vp;
} else {
@@ -804,46 +1437,56 @@ nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
else
nfsrv_vput(nd.ni_dvp);
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
- if (nfsd->nd_nqlflag == NQL_NOVAL) {
- tsize = fxdr_unsigned(long, sp->sa_nfssize);
- if (tsize != -1)
- vap->va_size = (u_quad_t)tsize;
- else
- vap->va_size = -1;
- } else
- fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
if (vap->va_size != -1) {
error = nfsrv_access(vp, VWRITE, cred,
- (nd.ni_cnd.cn_flags & RDONLY), nfsd->nd_procp);
- if (error) {
- nfsrv_vput(vp);
- nfsm_reply(0);
+ (nd.ni_cnd.cn_flags & RDONLY), procp);
+ if (!error) {
+ nqsrv_getl(vp, ND_WRITE);
+ tempsize = vap->va_size;
+ VATTR_NULL(vap);
+ vap->va_size = tempsize;
+ error = VOP_SETATTR(vp, vap, cred,
+ procp);
}
- nqsrv_getl(vp, NQL_WRITE);
- error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp);
- if (error) {
+ if (error)
nfsrv_vput(vp);
- nfsm_reply(0);
- }
}
}
- bzero((caddr_t)fhp, sizeof(nfh));
- fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
- error = VFS_VPTOFH(vp, &fhp->fh_fid);
- if (error) {
+ if (!error) {
+ bzero((caddr_t)fhp, sizeof(nfh));
+ fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+ error = VFS_VPTOFH(vp, &fhp->fh_fid);
+ if (!error)
+ error = VOP_GETATTR(vp, vap, cred, procp);
nfsrv_vput(vp);
- nfsm_reply(0);
}
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
- nfsrv_vput(vp);
- nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfhtom(fhp);
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfillattr;
- return (error);
+ if (v3) {
+ if (exclusive_flag && !error &&
+ bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
+ error = EEXIST;
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ }
+ nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
+ if (v3) {
+ if (!error) {
+ nfsm_srvpostop_fh(fhp);
+ nfsm_srvpostop_attr(0, vap);
+ }
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ } else {
+ nfsm_srvfhtom(fhp, v3);
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
+ nfsm_srvfillattr(vap, fp);
+ }
+ return (0);
nfsmout:
- if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags)
+ if (dirp)
+ nfsrv_vrele(dirp);
+ if (nd.ni_cnd.cn_nameiop) {
nfsrv_vrele(nd.ni_startdir);
+ free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ }
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == nd.ni_vp)
nfsrv_vrele(nd.ni_dvp);
@@ -852,79 +1495,248 @@ nfsmout:
if (nd.ni_vp)
nfsrv_vput(nd.ni_vp);
return (error);
+}
+
+/*
+ * nfs v3 mknod service
+ */
+int
+nfsrv_mknod(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
+{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register struct nfs_fattr *fp;
+ struct vattr va, dirfor, diraft;
+ register struct vattr *vap = &va;
+ register u_long *tl;
+ struct nameidata nd;
+ register caddr_t cp;
+ register long t1;
+ caddr_t bpos;
+ int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
+ u_long major, minor;
+ enum vtype vtyp;
+ char *cp2;
+ struct mbuf *mb, *mb2, *mreq;
+ struct vnode *vp, *dirp = (struct vnode *)0;
+ nfsfh_t nfh;
+ fhandle_t *fhp;
+ u_quad_t frev;
+ nd.ni_cnd.cn_nameiop = 0;
+ fhp = &nfh.fh_generic;
+ nfsm_srvmtofh(fhp);
+ nfsm_srvnamesiz(len);
+ nd.ni_cnd.cn_cred = cred;
+ nd.ni_cnd.cn_nameiop = CREATE;
+ nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
+ if (error) {
+ nfsm_reply(NFSX_WCCDATA(1));
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ if (dirp)
+ nfsrv_vrele(dirp);
+ return (0);
+ }
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ vtyp = nfsv3tov_type(*tl);
+ if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
+ nfsrv_vrele(nd.ni_startdir);
+ free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ error = NFSERR_BADTYPE;
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ nfsrv_vput(nd.ni_dvp);
+ goto out;
+ }
+ VATTR_NULL(vap);
+ nfsm_srvsattr(vap);
+ if (vtyp == VCHR || vtyp == VBLK) {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ major = fxdr_unsigned(u_long, *tl++);
+ minor = fxdr_unsigned(u_long, *tl);
+ vap->va_rdev = makedev(major, minor);
+ }
+
+ /*
+ * Iff doesn't exist, create it.
+ */
+ if (nd.ni_vp) {
+ nfsrv_vrele(nd.ni_startdir);
+ free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ error = EEXIST;
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ nfsrv_vput(nd.ni_dvp);
+ goto out;
+ }
+ vap->va_type = vtyp;
+ if (vtyp == VSOCK) {
+ nfsrv_vrele(nd.ni_startdir);
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
+ error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
+ if (!error)
+ FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ } else {
+ if (error = suser(cred, (u_short *)0)) {
+ nfsrv_vrele(nd.ni_startdir);
+ free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ nfsrv_vput(nd.ni_dvp);
+ goto out;
+ }
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
+ if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
+ nfsrv_vrele(nd.ni_startdir);
+ goto out;
+ }
+ nd.ni_cnd.cn_nameiop = LOOKUP;
+ nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
+ nd.ni_cnd.cn_proc = procp;
+ nd.ni_cnd.cn_cred = procp->p_ucred;
+ error = lookup(&nd);
+ FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ if (error)
+ goto out;
+ if (nd.ni_cnd.cn_flags & ISSYMLINK) {
+ nfsrv_vrele(nd.ni_dvp);
+ nfsrv_vput(nd.ni_vp);
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ error = EINVAL;
+ }
+ }
out:
- nfsrv_vrele(nd.ni_startdir);
- free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
- nfsm_reply(0);
+ vp = nd.ni_vp;
+ if (!error) {
+ bzero((caddr_t)fhp, sizeof(nfh));
+ fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+ error = VFS_VPTOFH(vp, &fhp->fh_fid);
+ if (!error)
+ error = VOP_GETATTR(vp, vap, cred, procp);
+ nfsrv_vput(vp);
+ }
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
+ if (!error) {
+ nfsm_srvpostop_fh(fhp);
+ nfsm_srvpostop_attr(0, vap);
+ }
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
return (0);
+nfsmout:
+ if (dirp)
+ nfsrv_vrele(dirp);
+ if (nd.ni_cnd.cn_nameiop) {
+ nfsrv_vrele(nd.ni_startdir);
+ free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ }
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ if (nd.ni_dvp == nd.ni_vp)
+ nfsrv_vrele(nd.ni_dvp);
+ else
+ nfsrv_vput(nd.ni_dvp);
+ if (nd.ni_vp)
+ nfsrv_vput(nd.ni_vp);
+ return (error);
}
/*
* nfs remove service
*/
int
-nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_remove(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
struct nameidata nd;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, cache, len;
+ int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
- struct mbuf *mb, *mreq;
- struct vnode *vp;
- nfsv2fh_t nfh;
+ struct mbuf *mb, *mreq, *mb2;
+ struct vnode *vp, *dirp;
+ struct vattr dirfor, diraft;
+ nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
+#ifndef nolint
+ vp = (struct vnode *)0;
+#endif
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = DELETE;
nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
- error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
- if (error)
- nfsm_reply(0);
- vp = nd.ni_vp;
- if (vp->v_type == VDIR &&
- (error = suser(cred, (u_short *)0)))
- goto out;
- /*
- * The root of a mounted filesystem cannot be deleted.
- */
- if (vp->v_flag & VROOT) {
- error = EBUSY;
- goto out;
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
+ procp);
+ else
+ nfsrv_vrele(dirp);
}
- (void) vnode_pager_uncache(vp);
-out:
if (!error) {
- int deallocobj = 0;
- nqsrv_getl(nd.ni_dvp, NQL_WRITE);
- nqsrv_getl(vp, NQL_WRITE);
-
- if ((vp->v_flag & VVMIO) && vp->v_vmdata)
- deallocobj = 1;
- error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
- if (error == 0 && deallocobj)
- vm_object_deallocate((vm_object_t) vp->v_vmdata);
- } else {
- VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
- if (nd.ni_dvp == vp)
- nfsrv_vrele(nd.ni_dvp);
- else
- nfsrv_vput(nd.ni_dvp);
- nfsrv_vput(vp);
+ vp = nd.ni_vp;
+ if (vp->v_type == VDIR &&
+ (error = suser(cred, (u_short *)0)))
+ goto out;
+ /*
+ * The root of a mounted filesystem cannot be deleted.
+ */
+ if (vp->v_flag & VROOT) {
+ error = EBUSY;
+ goto out;
+ }
+ if (vp->v_flag & VTEXT)
+ (void) vnode_pager_uncache(vp);
+out:
+ if (!error) {
+ int deallocobj = 0;
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
+ nqsrv_getl(vp, ND_WRITE);
+
+ if ((vp->v_flag & VVMIO) && vp->v_vmdata)
+ deallocobj = 1;
+ error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+ if (error == 0 && deallocobj)
+ vm_object_deallocate((vm_object_t) vp->v_vmdata);
+ } else {
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ if (nd.ni_dvp == vp)
+ nfsrv_vrele(nd.ni_dvp);
+ else
+ nfsrv_vput(nd.ni_dvp);
+ nfsrv_vput(vp);
+ }
+ }
+ if (dirp && v3) {
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ }
+ nfsm_reply(NFSX_WCCDATA(v3));
+ if (v3) {
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ return (0);
}
- nfsm_reply(0);
nfsm_srvdone;
}
@@ -932,32 +1744,42 @@ out:
* nfs rename service
*/
int
-nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_rename(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, cache, len, len2;
+ int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
+ int tdirfor_ret = 1, tdiraft_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
- struct mbuf *mb, *mreq;
+ struct mbuf *mb, *mreq, *mb2;
struct nameidata fromnd, tond;
- struct vnode *fvp = 0, *tvp, *tdvp;
- nfsv2fh_t fnfh, tnfh;
+ struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
+ struct vnode *tdirp = (struct vnode *)0;
+ struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
+ nfsfh_t fnfh, tnfh;
fhandle_t *ffhp, *tfhp;
u_quad_t frev;
uid_t saved_uid;
+#ifndef nolint
+ fvp = (struct vnode *)0;
+#endif
ffhp = &fnfh.fh_generic;
tfhp = &tnfh.fh_generic;
fromnd.ni_cnd.cn_nameiop = 0;
tond.ni_cnd.cn_nameiop = 0;
nfsm_srvmtofh(ffhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
/*
* Remember our original uid so that we can reset cr_uid before
* the second nfs_namei() call, in case it is remapped.
@@ -966,10 +1788,25 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
fromnd.ni_cnd.cn_cred = cred;
fromnd.ni_cnd.cn_nameiop = DELETE;
fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
- error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
- if(error)
- nfsm_reply(0);
+ error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
+ &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (fdirp) {
+ if (v3)
+ fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(fdirp);
+ fdirp = (struct vnode *)0;
+ }
+ }
+ if (error) {
+ nfsm_reply(2 * NFSX_WCCDATA(v3));
+ nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
+ nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
+ if (fdirp)
+ nfsrv_vrele(fdirp);
+ return (0);
+ }
fvp = fromnd.ni_vp;
nfsm_srvmtofh(tfhp);
nfsm_strsiz(len2, NFS_MAXNAMLEN);
@@ -977,8 +1814,17 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
tond.ni_cnd.cn_cred = cred;
tond.ni_cnd.cn_nameiop = RENAME;
tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
- error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md,
- &dpos, nfsd->nd_procp);
+ error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
+ &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (tdirp) {
+ if (v3)
+ tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(tdirp);
+ tdirp = (struct vnode *)0;
+ }
+ }
if (error) {
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
nfsrv_vrele(fromnd.ni_dvp);
@@ -989,27 +1835,45 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
tvp = tond.ni_vp;
if (tvp != NULL) {
if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
- error = EISDIR;
+ if (v3)
+ error = EEXIST;
+ else
+ error = EISDIR;
goto out;
} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
- error = ENOTDIR;
+ if (v3)
+ error = EEXIST;
+ else
+ error = ENOTDIR;
goto out;
}
if (tvp->v_type == VDIR && tvp->v_mountedhere) {
- error = EXDEV;
+ if (v3)
+ error = EXDEV;
+ else
+ error = ENOTEMPTY;
goto out;
}
}
if (fvp->v_type == VDIR && fvp->v_mountedhere) {
- error = EBUSY;
+ if (v3)
+ error = EXDEV;
+ else
+ error = ENOTEMPTY;
goto out;
}
if (fvp->v_mount != tdvp->v_mount) {
- error = EXDEV;
+ if (v3)
+ error = EXDEV;
+ else
+ error = ENOTEMPTY;
goto out;
}
if (fvp == tdvp)
- error = EINVAL;
+ if (v3)
+ error = EINVAL;
+ else
+ error = ENOTEMPTY;
/*
* If source is the same as the destination (that is the
* same vnode with the same name in the same directory),
@@ -1023,10 +1887,10 @@ nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
out:
if (!error) {
int deallocobjfrom = 0, deallocobjto = 0;
- nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
- nqsrv_getl(tdvp, NQL_WRITE);
+ nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
+ nqsrv_getl(tdvp, ND_WRITE);
if (tvp) {
- nqsrv_getl(tvp, NQL_WRITE);
+ nqsrv_getl(tvp, ND_WRITE);
if ((tvp->v_flag & VVMIO) && tvp->v_vmdata)
deallocobjto = 1;
}
@@ -1050,21 +1914,39 @@ out:
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
nfsrv_vrele(fromnd.ni_dvp);
nfsrv_vrele(fvp);
+ if (error == -1)
+ error = 0;
}
nfsrv_vrele(tond.ni_startdir);
FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
out1:
+ if (fdirp) {
+ fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
+ nfsrv_vrele(fdirp);
+ }
+ if (tdirp) {
+ tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
+ nfsrv_vrele(tdirp);
+ }
nfsrv_vrele(fromnd.ni_startdir);
FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
- nfsm_reply(0);
- return (error);
+ nfsm_reply(2 * NFSX_WCCDATA(v3));
+ if (v3) {
+ nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
+ nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
+ }
+ return (0);
nfsmout:
- if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) {
+ if (fdirp)
+ nfsrv_vrele(fdirp);
+ if (tdirp)
+ nfsrv_vrele(tdirp);
+ if (tond.ni_cnd.cn_nameiop) {
nfsrv_vrele(tond.ni_startdir);
FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
}
- if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) {
+ if (fromnd.ni_cnd.cn_nameiop) {
nfsrv_vrele(fromnd.ni_startdir);
FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
@@ -1078,22 +1960,27 @@ nfsmout:
* nfs link service
*/
int
-nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_link(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
struct nameidata nd;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, rdonly, cache, len;
+ int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
+ int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
- struct mbuf *mb, *mreq;
- struct vnode *vp, *xp;
- nfsv2fh_t nfh, dnfh;
+ struct mbuf *mb, *mreq, *mb2;
+ struct vnode *vp, *xp, *dirp = (struct vnode *)0;
+ struct vattr dirfor, diraft, at;
+ nfsfh_t nfh, dnfh;
fhandle_t *fhp, *dfhp;
u_quad_t frev;
@@ -1101,17 +1988,30 @@ nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
dfhp = &dnfh.fh_generic;
nfsm_srvmtofh(fhp);
nfsm_srvmtofh(dfhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
- error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
+ nfsm_srvnamesiz(len);
+ if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ return (0);
+ }
if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
goto out1;
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
nd.ni_cnd.cn_flags = LOCKPARENT;
- error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
+ error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(dirp);
+ dirp = (struct vnode *)0;
+ }
+ }
if (error)
goto out1;
xp = nd.ni_vp;
@@ -1124,9 +2024,13 @@ nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
error = EXDEV;
out:
if (!error) {
- nqsrv_getl(vp, NQL_WRITE);
- nqsrv_getl(xp, NQL_WRITE);
+ nqsrv_getl(vp, ND_WRITE);
+ nqsrv_getl(xp, ND_WRITE);
+#if defined(__FreeBSD__) || defined(__NetBSD__)
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+#else
+ error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
+#endif
} else {
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == nd.ni_vp)
@@ -1137,8 +2041,19 @@ out:
nfsrv_vrele(nd.ni_vp);
}
out1:
+ if (v3)
+ getret = VOP_GETATTR(vp, &at, cred, procp);
+ if (dirp) {
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ }
nfsrv_vrele(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
+ if (v3) {
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ return (0);
+ }
nfsm_srvdone;
}
@@ -1146,42 +2061,58 @@ out1:
* nfs symbolic link service
*/
int
-nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_symlink(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ struct vattr va, dirfor, diraft;
struct vnode *ovp;
- struct vattr va;
struct nameidata nd;
register struct vattr *vap = &va;
register u_long *tl;
register long t1;
struct nfsv2_sattr *sp;
- caddr_t bpos;
+ char *bpos, *cp, *pathcp = (char *)0, *cp2;
struct uio io;
struct iovec iv;
- int error = 0, cache, len, len2;
- char *pathcp, *cp2;
- struct mbuf *mb, *mreq;
- nfsv2fh_t nfh;
+ int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
+ struct mbuf *mb, *mreq, *mb2;
+ struct vnode *dirp = (struct vnode *)0;
+ nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
int deallocobj = 0;
- pathcp = (char *)0;
+ nd.ni_cnd.cn_nameiop = 0;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
- nd.ni_cnd.cn_flags = LOCKPARENT;
- error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
+ nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(dirp);
+ dirp = (struct vnode *)0;
+ }
+ }
if (error)
goto out;
+ VATTR_NULL(vap);
+ if (v3)
+ nfsm_srvsattr(vap);
nfsm_strsiz(len2, NFS_MAXPATHLEN);
MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
iv.iov_base = pathcp;
@@ -1194,9 +2125,14 @@ nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
io.uio_rw = UIO_READ;
io.uio_procp = (struct proc *)0;
nfsm_mtouio(&io, len2);
- nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
+ if (!v3) {
+ nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
+ }
*(pathcp + len2) = '\0';
if (nd.ni_vp) {
+ nfsrv_vrele(nd.ni_startdir);
+ free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == nd.ni_vp)
nfsrv_vrele(nd.ni_dvp);
@@ -1206,20 +2142,58 @@ nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
error = EEXIST;
goto out;
}
- VATTR_NULL(vap);
- vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
- nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
if ((ovp = nd.ni_vp) && (ovp->v_flag & VVMIO) && ovp->v_vmdata)
deallocobj = 1;
error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
if (error == 0 && deallocobj)
vm_object_deallocate( (vm_object_t) ovp->v_vmdata);
+ if (error)
+ nfsrv_vrele(nd.ni_startdir);
+ else {
+ if (v3) {
+ nd.ni_cnd.cn_nameiop = LOOKUP;
+ nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
+ nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
+ nd.ni_cnd.cn_proc = procp;
+ nd.ni_cnd.cn_cred = cred;
+ error = lookup(&nd);
+ if (!error) {
+ bzero((caddr_t)fhp, sizeof(nfh));
+ fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
+ error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
+ if (!error)
+ error = VOP_GETATTR(nd.ni_vp, vap, cred,
+ procp);
+ nfsrv_vput(nd.ni_vp);
+ }
+ } else
+ nfsrv_vrele(nd.ni_startdir);
+ FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ }
out:
if (pathcp)
FREE(pathcp, M_TEMP);
- nfsm_reply(0);
- return (error);
+ if (dirp) {
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ }
+ nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
+ if (v3) {
+ if (!error) {
+ nfsm_srvpostop_fh(fhp);
+ nfsm_srvpostop_attr(0, vap);
+ }
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ }
+ return (0);
nfsmout:
+ if (nd.ni_cnd.cn_nameiop) {
+ nfsrv_vrele(nd.ni_startdir);
+ free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
+ }
+ if (dirp)
+ nfsrv_vrele(dirp);
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == nd.ni_vp)
nfsrv_vrele(nd.ni_dvp);
@@ -1236,43 +2210,65 @@ nfsmout:
* nfs mkdir service
*/
int
-nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_mkdir(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
- struct vattr va;
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ struct vattr va, dirfor, diraft;
register struct vattr *vap = &va;
- register struct nfsv2_fattr *fp;
+ register struct nfs_fattr *fp;
struct nameidata nd;
register caddr_t cp;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, cache, len;
+ int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
struct mbuf *mb, *mb2, *mreq;
- struct vnode *vp;
- nfsv2fh_t nfh;
+ struct vnode *vp, *dirp = (struct vnode *)0;
+ nfsfh_t nfh;
fhandle_t *fhp;
u_quad_t frev;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
nd.ni_cnd.cn_flags = LOCKPARENT;
- error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
- if (error)
- nfsm_reply(0);
- nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(dirp);
+ dirp = (struct vnode *)0;
+ }
+ }
+ if (error) {
+ nfsm_reply(NFSX_WCCDATA(v3));
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ if (dirp)
+ nfsrv_vrele(dirp);
+ return (0);
+ }
VATTR_NULL(vap);
+ if (v3) {
+ nfsm_srvsattr(vap);
+ } else {
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ vap->va_mode = nfstov_mode(*tl++);
+ }
vap->va_type = VDIR;
- vap->va_mode = nfstov_mode(*tl++);
vp = nd.ni_vp;
if (vp != NULL) {
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
@@ -1282,28 +2278,40 @@ nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
nfsrv_vput(nd.ni_dvp);
nfsrv_vrele(vp);
error = EEXIST;
- nfsm_reply(0);
+ goto out;
}
- nqsrv_getl(nd.ni_dvp, NQL_WRITE);
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
- if (error)
- nfsm_reply(0);
- vp = nd.ni_vp;
- bzero((caddr_t)fhp, sizeof(nfh));
- fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
- error = VFS_VPTOFH(vp, &fhp->fh_fid);
- if (error) {
+ if (!error) {
+ vp = nd.ni_vp;
+ bzero((caddr_t)fhp, sizeof(nfh));
+ fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
+ error = VFS_VPTOFH(vp, &fhp->fh_fid);
+ if (!error)
+ error = VOP_GETATTR(vp, vap, cred, procp);
nfsrv_vput(vp);
- nfsm_reply(0);
}
- error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
- nfsrv_vput(vp);
- nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfhtom(fhp);
- nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
- nfsm_srvfillattr;
- return (error);
+out:
+ if (dirp) {
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ }
+ nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
+ if (v3) {
+ if (!error) {
+ nfsm_srvpostop_fh(fhp);
+ nfsm_srvpostop_attr(0, vap);
+ }
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ } else {
+ nfsm_srvfhtom(fhp, v3);
+ nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
+ nfsm_srvfillattr(vap, fp);
+ }
+ return (0);
nfsmout:
+ if (dirp)
+ nfsrv_vrele(dirp);
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == nd.ni_vp)
nfsrv_vrele(nd.ni_dvp);
@@ -1318,35 +2326,54 @@ nfsmout:
* nfs rmdir service
*/
int
-nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_rmdir(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, cache, len;
+ int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
- struct mbuf *mb, *mreq;
- struct vnode *vp;
- nfsv2fh_t nfh;
+ struct mbuf *mb, *mreq, *mb2;
+ struct vnode *vp, *dirp = (struct vnode *)0;
+ struct vattr dirfor, diraft;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct nameidata nd;
u_quad_t frev;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
+ nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = DELETE;
nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
- error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
- nfsd->nd_procp);
- if (error)
- nfsm_reply(0);
+ error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
+ &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
+ if (dirp) {
+ if (v3)
+ dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
+ procp);
+ else {
+ nfsrv_vrele(dirp);
+ dirp = (struct vnode *)0;
+ }
+ }
+ if (error) {
+ nfsm_reply(NFSX_WCCDATA(v3));
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ if (dirp)
+ nfsrv_vrele(dirp);
+ return (0);
+ }
vp = nd.ni_vp;
if (vp->v_type != VDIR) {
error = ENOTDIR;
@@ -1366,8 +2393,8 @@ nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
error = EBUSY;
out:
if (!error) {
- nqsrv_getl(nd.ni_dvp, NQL_WRITE);
- nqsrv_getl(vp, NQL_WRITE);
+ nqsrv_getl(nd.ni_dvp, ND_WRITE);
+ nqsrv_getl(vp, ND_WRITE);
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
} else {
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
@@ -1377,7 +2404,15 @@ out:
nfsrv_vput(nd.ni_dvp);
nfsrv_vput(vp);
}
- nfsm_reply(0);
+ if (dirp) {
+ diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
+ nfsrv_vrele(dirp);
+ }
+ nfsm_reply(NFSX_WCCDATA(v3));
+ if (v3) {
+ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
+ return (0);
+ }
nfsm_srvdone;
}
@@ -1401,7 +2436,7 @@ out:
* than requested, but this may not apply to all filesystems. For
* example, client NFS does not { although it is never remote mounted
* anyhow }
- * The alternate call nqnfsrv_readdirlook() does lookups as well.
+ * The alternate call nfsrv_readdirplus() does lookups as well.
* PS: The NFS protocol spec. does not clarify what the "count" byte
* argument is a count of.. just name strings and file id's or the
* entire reply rpc or ...
@@ -1411,21 +2446,25 @@ out:
* "entry" structures, but are in the rpc.
*/
struct flrep {
- u_long fl_cachable;
- u_long fl_duration;
- u_long fl_frev[2];
- nfsv2fh_t fl_nfh;
- u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)];
+ nfsuint64 fl_off;
+ u_long fl_postopok;
+ u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
+ u_long fl_fhok;
+ u_long fl_fhsize;
+ u_long fl_nfh[NFSX_V3FH / sizeof (u_long)];
};
int
-nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_readdir(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register char *bp, *be;
register struct mbuf *mp;
register struct dirent *dp;
@@ -1436,38 +2475,63 @@ nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
struct mbuf *mb, *mb2, *mreq, *mp2;
char *cpos, *cend, *cp2, *rbuf;
struct vnode *vp;
- nfsv2fh_t nfh;
+ struct vattr at;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct uio io;
struct iovec iv;
- int len, nlen, rem, xfer, tsiz, i, error = 0;
- int siz, cnt, fullsiz, eofflag, rdonly, cache;
- u_quad_t frev;
- u_long off, toff;
- int ncookies;
- u_int *cookies;
- u_int *cookiep;
+ int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
+ int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
+ u_quad_t frev, off, toff, verf;
+ u_long *cookies = NULL, *cookiep;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
- off = toff = fxdr_unsigned(u_long, *tl++);
+ if (v3) {
+ nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
+ fxdr_hyper(tl, &toff);
+ tl += 2;
+ fxdr_hyper(tl, &verf);
+ tl += 2;
+ } else {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ toff = fxdr_unsigned(u_quad_t, *tl++);
+ }
+ off = toff;
cnt = fxdr_unsigned(int, *tl);
- siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
- if (cnt > NFS_MAXREADDIR)
- siz = NFS_MAXREADDIR;
+ siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
+ xfer = NFS_SRVMAXDATA(nfsd);
+ if (siz > xfer)
+ siz = xfer;
fullsiz = siz;
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
- nqsrv_getl(vp, NQL_READ);
- error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
+ }
+ nqsrv_getl(vp, ND_READ);
+ if (v3) {
+ error = getret = VOP_GETATTR(vp, &at, cred, procp);
+ if (!error && toff && verf != at.va_filerev)
+ error = NFSERR_BAD_COOKIE;
+ }
+ if (!error)
+ error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
if (error) {
nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_POSTOPATTR(v3));
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
}
VOP_UNLOCK(vp);
MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
+#ifdef __NetBSD__
+ ncookies = siz / (5 * NFSX_UNSIGNED); /*7 for V3, but it's an est. so*/
+ MALLOC(cookies, u_long *, ncookies * sizeof (u_long *), M_TEMP,
+ M_WAITOK);
+#endif
again:
iv.iov_base = rbuf;
iv.iov_len = fullsiz;
@@ -1478,25 +2542,31 @@ again:
io.uio_segflg = UIO_SYSSPACE;
io.uio_rw = UIO_READ;
io.uio_procp = (struct proc *)0;
- cookies = NULL;
eofflag = 0;
+#ifndef __NetBSD__
+ if (cookies) {
+ free((caddr_t)cookies, M_TEMP);
+ cookies = NULL;
+ }
error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
+#else
+ error = VOP_READDIR(vp, &io, cred, &eofflag, cookies, ncookies);
+#endif
off = (off_t)io.uio_offset;
+ if (!cookies && !error)
+ error = NFSERR_PERM;
+ if (v3) {
+ getret = VOP_GETATTR(vp, &at, cred, procp);
+ if (!error)
+ error = getret;
+ }
if (error) {
nfsrv_vrele(vp);
free((caddr_t)rbuf, M_TEMP);
- nfsm_reply(0);
- }
- if (cookies == NULL) {
- /*
- * If the filesystem doen't support cookies, return eof.
- */
- nfsrv_vrele(vp);
- nfsm_reply(2*NFSX_UNSIGNED);
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = nfs_false;
- *tl = nfs_true;
- FREE((caddr_t)rbuf, M_TEMP);
+ if (cookies)
+ free((caddr_t)cookies, M_TEMP);
+ nfsm_reply(NFSX_POSTOPATTR(v3));
+ nfsm_srvpostop_attr(getret, &at);
return (0);
}
if (io.uio_resid) {
@@ -1508,12 +2578,19 @@ again:
*/
if (siz == 0) {
nfsrv_vrele(vp);
- nfsm_reply(2*NFSX_UNSIGNED);
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
+ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
+ 2 * NFSX_UNSIGNED);
+ if (v3) {
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
+ txdr_hyper(&at.va_filerev, tl);
+ tl += 2;
+ } else
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
*tl++ = nfs_false;
*tl = nfs_true;
FREE((caddr_t)rbuf, M_TEMP);
- FREE(cookies, M_TEMP);
+ FREE((caddr_t)cookies, M_TEMP);
return (0);
}
}
@@ -1526,32 +2603,49 @@ again:
cend = rbuf + siz;
dp = (struct dirent *)cpos;
cookiep = cookies;
- while (cpos < cend && ncookies > 0
- && (*cookiep <= toff || dp->d_fileno == 0)) {
+#ifdef __FreeBSD__
+ /*
+ * For some reason FreeBSD's ufs_readdir() chooses to back the
+ * directory offset up to a block boundary, so it is necessary to
+ * skip over the records that preceed the requested offset. This
+ * requires the assumption that file offset cookies monotonically
+ * increase.
+ */
+ while (cpos < cend && ncookies > 0 &&
+ (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
+#else
+ while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
+#endif
cpos += dp->d_reclen;
dp = (struct dirent *)cpos;
cookiep++;
ncookies--;
}
- if (cpos >= cend) {
+ if (cpos >= cend || ncookies == 0) {
toff = off;
siz = fullsiz;
- FREE(cookies, M_TEMP);
goto again;
}
- len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
- nfsm_reply(siz);
+ len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
+ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
+ if (v3) {
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ txdr_hyper(&at.va_filerev, tl);
+ }
mp = mp2 = mb;
bp = bpos;
be = bp + M_TRAILINGSPACE(mp);
/* Loop through the records and build reply */
- while (cpos < cend) {
+ while (cpos < cend && ncookies > 0) {
if (dp->d_fileno != 0) {
nlen = dp->d_namlen;
rem = nfsm_rndup(nlen)-nlen;
- len += (4*NFSX_UNSIGNED + nlen + rem);
+ len += (4 * NFSX_UNSIGNED + nlen + rem);
+ if (v3)
+ len += 2 * NFSX_UNSIGNED;
if (len > cnt) {
eofflag = 0;
break;
@@ -1563,6 +2657,11 @@ again:
nfsm_clget;
*tl = nfs_true;
bp += NFSX_UNSIGNED;
+ if (v3) {
+ nfsm_clget;
+ *tl = 0;
+ bp += NFSX_UNSIGNED;
+ }
nfsm_clget;
*tl = txdr_unsigned(dp->d_fileno);
bp += NFSX_UNSIGNED;
@@ -1591,12 +2690,18 @@ again:
nfsm_clget;
/* Finish off the record */
+ if (v3) {
+ *tl = 0;
+ bp += NFSX_UNSIGNED;
+ nfsm_clget;
+ }
*tl = txdr_unsigned(*cookiep);
bp += NFSX_UNSIGNED;
}
cpos += dp->d_reclen;
dp = (struct dirent *)cpos;
cookiep++;
+ ncookies--;
}
nfsrv_vrele(vp);
nfsm_clget;
@@ -1613,19 +2718,22 @@ again:
mp->m_len = bp - mtod(mp, caddr_t);
} else
mp->m_len += bp - bpos;
- FREE(rbuf, M_TEMP);
- FREE(cookies, M_TEMP);
+ FREE((caddr_t)rbuf, M_TEMP);
+ FREE((caddr_t)cookies, M_TEMP);
nfsm_srvdone;
}
int
-nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_readdirplus(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register char *bp, *be;
register struct mbuf *mp;
register struct dirent *dp;
@@ -1637,42 +2745,58 @@ nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
char *cpos, *cend, *cp2, *rbuf;
struct vnode *vp, *nvp;
struct flrep fl;
- nfsv2fh_t nfh;
- fhandle_t *fhp;
+ nfsfh_t nfh;
+ fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
struct uio io;
struct iovec iv;
- struct vattr va, *vap = &va;
- struct nfsv2_fattr *fp;
- int len, nlen, rem, xfer, tsiz, i, error = 0, cache2;
- int siz, cnt, fullsiz, eofflag, rdonly, cache;
- u_long duration2;
- u_quad_t frev, frev2;
- u_long off, toff;
- int ncookies;
- u_int *cookies;
- u_int *cookiep;
+ struct vattr va, at, *vap = &va;
+ struct nfs_fattr *fp;
+ int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
+ int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
+ u_quad_t frev, off, toff, verf;
+ u_long *cookies = NULL, *cookiep;
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
- nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
- toff = off = fxdr_unsigned(u_long, *tl++);
- cnt = fxdr_unsigned(int, *tl++);
- duration2 = fxdr_unsigned(int, *tl);
- siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
- if (cnt > NFS_MAXREADDIR)
- siz = NFS_MAXREADDIR;
+ nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
+ fxdr_hyper(tl, &toff);
+ tl += 2;
+ fxdr_hyper(tl, &verf);
+ tl += 2;
+ siz = fxdr_unsigned(int, *tl++);
+ cnt = fxdr_unsigned(int, *tl);
+ off = toff;
+ siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
+ xfer = NFS_SRVMAXDATA(nfsd);
+ if (siz > xfer)
+ siz = xfer;
fullsiz = siz;
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
- nqsrv_getl(vp, NQL_READ);
- error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
+ }
+ error = getret = VOP_GETATTR(vp, &at, cred, procp);
+ if (!error && toff && verf != at.va_filerev)
+ error = NFSERR_BAD_COOKIE;
+ if (!error) {
+ nqsrv_getl(vp, ND_READ);
+ error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
+ }
if (error) {
nfsrv_vput(vp);
- nfsm_reply(0);
+ nfsm_reply(NFSX_V3POSTOPATTR);
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
}
VOP_UNLOCK(vp);
MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
+#ifdef __NetBSD__
+ ncookies = siz / (7 * NFSX_UNSIGNED);
+ MALLOC(cookies, u_long *, ncookies * sizeof (u_long *), M_TEMP,
+ M_WAITOK);
+#endif
again:
iv.iov_base = rbuf;
iv.iov_len = fullsiz;
@@ -1683,25 +2807,29 @@ again:
io.uio_segflg = UIO_SYSSPACE;
io.uio_rw = UIO_READ;
io.uio_procp = (struct proc *)0;
- cookies = NULL;
eofflag = 0;
+#ifndef __NetBSD__
+ if (cookies) {
+ free((caddr_t)cookies, M_TEMP);
+ cookies = NULL;
+ }
error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
- off = (u_long)io.uio_offset;
+#else
+ error = VOP_READDIR(vp, &io, cred, &eofflag, cookies, ncookies);
+#endif
+ off = (u_quad_t)io.uio_offset;
+ getret = VOP_GETATTR(vp, &at, cred, procp);
+ if (!cookies && !error)
+ error = NFSERR_PERM;
+ if (!error)
+ error = getret;
if (error) {
nfsrv_vrele(vp);
+ if (cookies)
+ free((caddr_t)cookies, M_TEMP);
free((caddr_t)rbuf, M_TEMP);
- nfsm_reply(0);
- }
- if (cookies == NULL) {
- /*
- * If the filesystem doen't support cookies, return eof.
- */
- nfsrv_vrele(vp);
- nfsm_reply(2*NFSX_UNSIGNED);
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = nfs_false;
- *tl = nfs_true;
- FREE((caddr_t)rbuf, M_TEMP);
+ nfsm_reply(NFSX_V3POSTOPATTR);
+ nfsm_srvpostop_attr(getret, &at);
return (0);
}
if (io.uio_resid) {
@@ -1713,12 +2841,16 @@ again:
*/
if (siz == 0) {
nfsrv_vrele(vp);
- nfsm_reply(2 * NFSX_UNSIGNED);
- nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
+ 2 * NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
+ txdr_hyper(&at.va_filerev, tl);
+ tl += 2;
*tl++ = nfs_false;
*tl = nfs_true;
+ FREE((caddr_t)cookies, M_TEMP);
FREE((caddr_t)rbuf, M_TEMP);
- FREE(cookies, M_TEMP);
return (0);
}
}
@@ -1731,28 +2863,41 @@ again:
cend = rbuf + siz;
dp = (struct dirent *)cpos;
cookiep = cookies;
- while (cpos < cend && ncookies > 0
- && (*cookiep <= toff || dp->d_fileno == 0)) {
+#ifdef __FreeBSD__
+ /*
+ * For some reason FreeBSD's ufs_readdir() chooses to back the
+ * directory offset up to a block boundary, so it is necessary to
+ * skip over the records that preceed the requested offset. This
+ * requires the assumption that file offset cookies monotonically
+ * increase.
+ */
+ while (cpos < cend && ncookies > 0 &&
+ (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
+#else
+ while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
+#endif
cpos += dp->d_reclen;
dp = (struct dirent *)cpos;
cookiep++;
ncookies--;
}
- if (cpos >= cend) {
+ if (cpos >= cend || ncookies == 0) {
toff = off;
siz = fullsiz;
- FREE(cookies, M_TEMP);
goto again;
}
- len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
- nfsm_reply(siz);
+ dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
+ nfsm_reply(cnt);
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ txdr_hyper(&at.va_filerev, tl);
mp = mp2 = mb;
bp = bpos;
be = bp + M_TRAILINGSPACE(mp);
/* Loop through the records and build reply */
- while (cpos < cend) {
+ while (cpos < cend && ncookies > 0) {
if (dp->d_fileno != 0) {
nlen = dp->d_namlen;
rem = nfsm_rndup(nlen)-nlen;
@@ -1763,59 +2908,51 @@ again:
*/
if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
goto invalid;
- bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
- fl.fl_nfh.fh_generic.fh_fsid =
+ bzero((caddr_t)nfhp, NFSX_V3FH);
+ nfhp->fh_fsid =
nvp->v_mount->mnt_stat.f_fsid;
- if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) {
+ if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
vput(nvp);
goto invalid;
}
- if (duration2) {
- (void) nqsrv_getlease(nvp, &duration2, NQL_READ,
- nfsd, nam, &cache2, &frev2, cred);
- fl.fl_duration = txdr_unsigned(duration2);
- fl.fl_cachable = txdr_unsigned(cache2);
- txdr_hyper(&frev2, fl.fl_frev);
- } else
- fl.fl_duration = 0;
- if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
+ if (VOP_GETATTR(nvp, vap, cred, procp)) {
vput(nvp);
goto invalid;
}
vput(nvp);
- fp = (struct nfsv2_fattr *)&fl.fl_fattr;
- nfsm_srvfillattr;
- len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
- + NFSX_NQFATTR);
- if (len > cnt) {
+
+ /*
+ * If either the dircount or maxcount will be
+ * exceeded, get out now. Both of these lengths
+ * are calculated conservatively, including all
+ * XDR overheads.
+ */
+ len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
+ NFSX_V3POSTOPATTR);
+ dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
+ if (len > cnt || dirlen > fullsiz) {
eofflag = 0;
break;
}
+
/*
* Build the directory record xdr from
* the dirent entry.
*/
+ fp = (struct nfs_fattr *)&fl.fl_fattr;
+ nfsm_srvfillattr(vap, fp);
+ fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
+ fl.fl_fhok = nfs_true;
+ fl.fl_postopok = nfs_true;
+ fl.fl_off.nfsuquad[0] = 0;
+ fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
+
nfsm_clget;
*tl = nfs_true;
bp += NFSX_UNSIGNED;
-
- /*
- * For readdir_and_lookup copy the stuff out.
- */
- xfer = sizeof (struct flrep);
- cp = (caddr_t)&fl;
- while (xfer > 0) {
- nfsm_clget;
- if ((bp+xfer) > be)
- tsiz = be-bp;
- else
- tsiz = xfer;
- bcopy(cp, bp, tsiz);
- bp += tsiz;
- xfer -= tsiz;
- if (xfer > 0)
- cp += tsiz;
- }
+ nfsm_clget;
+ *tl = 0;
+ bp += NFSX_UNSIGNED;
nfsm_clget;
*tl = txdr_unsigned(dp->d_fileno);
bp += NFSX_UNSIGNED;
@@ -1828,8 +2965,8 @@ again:
cp = dp->d_name;
while (xfer > 0) {
nfsm_clget;
- if ((bp+xfer) > be)
- tsiz = be-bp;
+ if ((bp + xfer) > be)
+ tsiz = be - bp;
else
tsiz = xfer;
bcopy(cp, bp, tsiz);
@@ -1841,16 +2978,30 @@ again:
/* And null pad to a long boundary */
for (i = 0; i < rem; i++)
*bp++ = '\0';
- nfsm_clget;
-
- /* Finish off the record */
- *tl = txdr_unsigned(*cookiep);
- bp += NFSX_UNSIGNED;
+
+ /*
+ * Now copy the flrep structure out.
+ */
+ xfer = sizeof (struct flrep);
+ cp = (caddr_t)&fl;
+ while (xfer > 0) {
+ nfsm_clget;
+ if ((bp + xfer) > be)
+ tsiz = be - bp;
+ else
+ tsiz = xfer;
+ bcopy(cp, bp, tsiz);
+ bp += tsiz;
+ xfer -= tsiz;
+ if (xfer > 0)
+ cp += tsiz;
+ }
}
invalid:
cpos += dp->d_reclen;
dp = (struct dirent *)cpos;
cookiep++;
+ ncookies--;
}
nfsrv_vrele(vp);
nfsm_clget;
@@ -1867,8 +3018,69 @@ invalid:
mp->m_len = bp - mtod(mp, caddr_t);
} else
mp->m_len += bp - bpos;
- FREE(rbuf, M_TEMP);
- FREE(cookies, M_TEMP);
+ FREE((caddr_t)cookies, M_TEMP);
+ FREE((caddr_t)rbuf, M_TEMP);
+ nfsm_srvdone;
+}
+
+/*
+ * nfs commit service
+ */
+int
+nfsrv_commit(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
+{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ struct vattr bfor, aft;
+ struct vnode *vp;
+ nfsfh_t nfh;
+ fhandle_t *fhp;
+ register u_long *tl;
+ register long t1;
+ caddr_t bpos;
+ int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
+ char *cp2;
+ struct mbuf *mb, *mb2, *mreq;
+ u_quad_t frev, off;
+
+#ifndef nolint
+ cache = 0;
+#endif
+ fhp = &nfh.fh_generic;
+ nfsm_srvmtofh(fhp);
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+
+ /*
+ * XXX At this time VOP_FSYNC() does not accept offset and byte
+ * count parameters, so these arguments are useless (someday maybe).
+ */
+ fxdr_hyper(tl, &off);
+ tl += 2;
+ cnt = fxdr_unsigned(int, *tl);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(2 * NFSX_UNSIGNED);
+ nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
+ return (0);
+ }
+ for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
+ error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
+ aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
+ nfsrv_vput(vp);
+ nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
+ nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
+ if (!error) {
+ nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
+ *tl++ = txdr_unsigned(boottime.tv_sec);
+ *tl = txdr_unsigned(boottime.tv_usec);
+ } else
+ return (0);
nfsm_srvdone;
}
@@ -1876,69 +3088,244 @@ invalid:
* nfs statfs service
*/
int
-nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_statfs(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
register struct statfs *sf;
- register struct nfsv2_statfs *sfp;
+ register struct nfs_statfs *sfp;
register u_long *tl;
register long t1;
caddr_t bpos;
- int error = 0, rdonly, cache = 0, isnq;
+ int error = 0, rdonly, cache, getret = 1;
+ int v3 = (nfsd->nd_flag & ND_NFSV3);
char *cp2;
struct mbuf *mb, *mb2, *mreq;
struct vnode *vp;
- nfsv2fh_t nfh;
+ struct vattr at;
+ nfsfh_t nfh;
fhandle_t *fhp;
struct statfs statfs;
- u_quad_t frev;
+ u_quad_t frev, tval;
+#ifndef nolint
+ cache = 0;
+#endif
fhp = &nfh.fh_generic;
- isnq = (nfsd->nd_nqlflag != NQL_NOVAL);
nfsm_srvmtofh(fhp);
- error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly);
- if (error)
- nfsm_reply(0);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
+ }
sf = &statfs;
- error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
+ error = VFS_STATFS(vp->v_mount, sf, procp);
+ getret = VOP_GETATTR(vp, &at, cred, procp);
nfsrv_vput(vp);
- nfsm_reply(NFSX_STATFS(isnq));
- nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
- sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
- sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
- sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
- sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
- sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
- if (isnq) {
- sfp->sf_files = txdr_unsigned(sf->f_files);
- sfp->sf_ffree = txdr_unsigned(sf->f_ffree);
+ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
+ if (v3)
+ nfsm_srvpostop_attr(getret, &at);
+ if (error)
+ return (0);
+ nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
+ if (v3) {
+ tval = (u_quad_t)sf->f_blocks;
+ tval *= (u_quad_t)sf->f_bsize;
+ txdr_hyper(&tval, &sfp->sf_tbytes);
+ tval = (u_quad_t)sf->f_bfree;
+ tval *= (u_quad_t)sf->f_bsize;
+ txdr_hyper(&tval, &sfp->sf_fbytes);
+ tval = (u_quad_t)sf->f_bavail;
+ tval *= (u_quad_t)sf->f_bsize;
+ txdr_hyper(&tval, &sfp->sf_abytes);
+ sfp->sf_tfiles.nfsuquad[0] = 0;
+ sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
+ sfp->sf_ffiles.nfsuquad[0] = 0;
+ sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
+ sfp->sf_afiles.nfsuquad[0] = 0;
+ sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
+ sfp->sf_invarsec = 0;
+ } else {
+ sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
+ sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
+ sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
+ sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
+ sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
}
nfsm_srvdone;
}
/*
+ * nfs fsinfo service
+ */
+int
+nfsrv_fsinfo(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
+{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register u_long *tl;
+ register struct nfsv3_fsinfo *sip;
+ register long t1;
+ caddr_t bpos;
+ int error = 0, rdonly, cache, getret = 1, pref;
+ char *cp2;
+ struct mbuf *mb, *mb2, *mreq;
+ struct vnode *vp;
+ struct vattr at;
+ nfsfh_t nfh;
+ fhandle_t *fhp;
+ u_quad_t frev;
+
+#ifndef nolint
+ cache = 0;
+#endif
+ fhp = &nfh.fh_generic;
+ nfsm_srvmtofh(fhp);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
+ }
+ getret = VOP_GETATTR(vp, &at, cred, procp);
+ nfsrv_vput(vp);
+ nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
+ nfsm_srvpostop_attr(getret, &at);
+ nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
+
+ /*
+ * XXX
+ * There should be file system VFS OP(s) to get this information.
+ * For now, assume ufs.
+ */
+ if (slp->ns_so->so_type == SOCK_DGRAM)
+ pref = NFS_MAXDGRAMDATA;
+ else
+ pref = NFS_MAXDATA;
+ sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
+ sip->fs_rtpref = txdr_unsigned(pref);
+ sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
+ sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
+ sip->fs_wtpref = txdr_unsigned(pref);
+ sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
+ sip->fs_dtpref = txdr_unsigned(pref);
+ sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
+ sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
+ sip->fs_timedelta.nfsv3_sec = 0;
+ sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
+ sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
+ NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
+ NFSV3FSINFO_CANSETTIME);
+ nfsm_srvdone;
+}
+
+/*
+ * nfs pathconf service
+ */
+int
+nfsrv_pathconf(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
+{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
+ register u_long *tl;
+ register struct nfsv3_pathconf *pc;
+ register long t1;
+ caddr_t bpos;
+ int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
+ int chownres, notrunc;
+ char *cp2;
+ struct mbuf *mb, *mb2, *mreq;
+ struct vnode *vp;
+ struct vattr at;
+ nfsfh_t nfh;
+ fhandle_t *fhp;
+ u_quad_t frev;
+
+#ifndef nolint
+ cache = 0;
+#endif
+ fhp = &nfh.fh_generic;
+ nfsm_srvmtofh(fhp);
+ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
+ &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
+ nfsm_reply(NFSX_UNSIGNED);
+ nfsm_srvpostop_attr(getret, &at);
+ return (0);
+ }
+ error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
+ if (!error)
+ error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
+ if (!error)
+ error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
+ if (!error)
+ error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
+ getret = VOP_GETATTR(vp, &at, cred, procp);
+ nfsrv_vput(vp);
+ nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
+ nfsm_srvpostop_attr(getret, &at);
+ if (error)
+ return (0);
+ nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
+
+ pc->pc_linkmax = txdr_unsigned(linkmax);
+ pc->pc_namemax = txdr_unsigned(namemax);
+ pc->pc_notrunc = txdr_unsigned(notrunc);
+ pc->pc_chownrestricted = txdr_unsigned(chownres);
+
+ /*
+ * These should probably be supported by VOP_PATHCONF(), but
+ * until msdosfs is exportable (why would you want to?), the
+ * Unix defaults should be ok.
+ */
+ pc->pc_caseinsensitive = nfs_false;
+ pc->pc_casepreserving = nfs_true;
+ nfsm_srvdone;
+}
+
+/*
* Null operation, used by clients to ping server
*/
/* ARGSUSED */
int
-nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_null(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
caddr_t bpos;
- int error = VNOVAL, cache = 0;
+ int error = NFSERR_RETVOID, cache;
struct mbuf *mb, *mreq;
u_quad_t frev;
+#ifndef nolint
+ cache = 0;
+#endif
nfsm_reply(0);
- return (error);
+ return (0);
}
/*
@@ -1946,24 +3333,30 @@ nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
*/
/* ARGSUSED */
int
-nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq)
- struct nfsd *nfsd;
- struct mbuf *mrep, *md;
- caddr_t dpos;
- struct ucred *cred;
- struct mbuf *nam, **mrq;
+nfsrv_noop(nfsd, slp, procp, mrq)
+ struct nfsrv_descript *nfsd;
+ struct nfssvc_sock *slp;
+ struct proc *procp;
+ struct mbuf **mrq;
{
+ struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
+ struct mbuf *nam = nfsd->nd_nam;
+ caddr_t dpos = nfsd->nd_dpos;
+ struct ucred *cred = &nfsd->nd_cr;
caddr_t bpos;
- int error, cache = 0;
+ int error, cache;
struct mbuf *mb, *mreq;
u_quad_t frev;
+#ifndef nolint
+ cache = 0;
+#endif
if (nfsd->nd_repstat)
error = nfsd->nd_repstat;
else
error = EPROCUNAVAIL;
nfsm_reply(0);
- return (error);
+ return (0);
}
/*
@@ -1997,8 +3390,6 @@ nfsrv_access(vp, flags, cred, rdonly, p)
switch (vp->v_type) {
case VREG: case VDIR: case VLNK:
return (EROFS);
- default:
- break;
}
}
/*
@@ -2008,8 +3399,7 @@ nfsrv_access(vp, flags, cred, rdonly, p)
if (vp->v_flag & VTEXT)
return (ETXTBSY);
}
- error = VOP_GETATTR(vp, &vattr, cred, p);
- if (error)
+ if (error = VOP_GETATTR(vp, &vattr, cred, p))
return (error);
if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
cred->cr_uid != vattr.va_uid)
diff --git a/sys/nfs/nfs_socket.c b/sys/nfs/nfs_socket.c
index 20253efb018b..8d15b24dad85 100644
--- a/sys/nfs/nfs_socket.c
+++ b/sys/nfs/nfs_socket.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_socket.c 8.3 (Berkeley) 1/12/94
- * $Id: nfs_socket.c,v 1.6 1995/03/16 18:15:37 bde Exp $
+ * $Id: nfs_socket.c,v 1.7 1995/05/30 08:12:40 rgrimes Exp $
*/
/*
@@ -59,7 +59,7 @@
#include <netinet/tcp.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
@@ -94,36 +94,13 @@
* External data, mostly RPC constants in XDR form
*/
extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
- rpc_msgaccepted, rpc_call, rpc_autherr, rpc_rejectedcred,
+ rpc_msgaccepted, rpc_call, rpc_autherr,
rpc_auth_kerb;
-extern u_long nfs_prog, nfs_vers, nqnfs_prog, nqnfs_vers;
+extern u_long nfs_prog, nqnfs_prog;
extern time_t nqnfsstarttime;
-extern int nonidempotent[NFS_NPROCS];
-
-/*
- * Maps errno values to nfs error numbers.
- * Use NFSERR_IO as the catch all for ones not specifically defined in
- * RFC 1094.
- */
-static int nfsrv_errmap[ELAST] = {
- NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
- NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
- NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO,
-};
+extern struct nfsstats nfsstats;
+extern int nfsv3_procid[NFS_NPROCS];
+extern int nfs_ticks;
/*
* Defines which timer to use for the procnum.
@@ -134,7 +111,8 @@ static int nfsrv_errmap[ELAST] = {
* 4 - write
*/
static int proct[NFS_NPROCS] = {
- 0, 1, 0, 0, 2, 3, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0,
+ 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0,
+ 0, 0, 0,
};
/*
@@ -164,10 +142,12 @@ int nfsrv_null(),
nfsrv_getattr(),
nfsrv_setattr(),
nfsrv_lookup(),
+ nfsrv3_access(),
nfsrv_readlink(),
nfsrv_read(),
nfsrv_write(),
nfsrv_create(),
+ nfsrv_mknod(),
nfsrv_remove(),
nfsrv_rename(),
nfsrv_link(),
@@ -175,37 +155,42 @@ int nfsrv_null(),
nfsrv_mkdir(),
nfsrv_rmdir(),
nfsrv_readdir(),
+ nfsrv_readdirplus(),
nfsrv_statfs(),
+ nfsrv_fsinfo(),
+ nfsrv_pathconf(),
+ nfsrv_commit(),
nfsrv_noop(),
- nqnfsrv_readdirlook(),
nqnfsrv_getlease(),
- nqnfsrv_vacated(),
- nqnfsrv_access();
+ nqnfsrv_vacated();
-int (*nfsrv_procs[NFS_NPROCS])() = {
+int (*nfsrv3_procs[NFS_NPROCS])() = {
nfsrv_null,
nfsrv_getattr,
nfsrv_setattr,
- nfsrv_noop,
nfsrv_lookup,
+ nfsrv3_access,
nfsrv_readlink,
nfsrv_read,
- nfsrv_noop,
nfsrv_write,
nfsrv_create,
+ nfsrv_mkdir,
+ nfsrv_symlink,
+ nfsrv_mknod,
nfsrv_remove,
+ nfsrv_rmdir,
nfsrv_rename,
nfsrv_link,
- nfsrv_symlink,
- nfsrv_mkdir,
- nfsrv_rmdir,
nfsrv_readdir,
+ nfsrv_readdirplus,
nfsrv_statfs,
- nqnfsrv_readdirlook,
+ nfsrv_fsinfo,
+ nfsrv_pathconf,
+ nfsrv_commit,
nqnfsrv_getlease,
nqnfsrv_vacated,
nfsrv_noop,
- nqnfsrv_access,
+ nfsrv_noop
};
/*
@@ -874,13 +859,16 @@ nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp)
struct nfsmount *nmp;
struct mbuf *md, *mheadend;
struct nfsnode *np;
+ char nickv[RPCX_NICKVERF];
time_t reqtime, waituntil;
caddr_t dpos, cp2;
int t1, nqlflag, cachable, s, error = 0, mrest_len, auth_len, auth_type;
int trylater_delay = NQ_TRYLATERDEL, trylater_cnt = 0, failed_auth = 0;
+ int verf_len, verf_type;
u_long xid;
u_quad_t frev;
- char *auth_str;
+ char *auth_str, *verf_str;
+ NFSKERBKEY_T key; /* save session key */
nmp = VFSTONFS(vp->v_mount);
MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
@@ -900,19 +888,21 @@ nfs_request(vp, mrest, procnum, procp, cred, mrp, mdp, dposp)
* Get the RPC header with authorization.
*/
kerbauth:
- auth_str = (char *)0;
+ verf_str = auth_str = (char *)0;
if (nmp->nm_flag & NFSMNT_KERB) {
- if (failed_auth) {
- error = nfs_getauth(nmp, rep, cred, &auth_type,
- &auth_str, &auth_len);
+ verf_str = nickv;
+ verf_len = sizeof (nickv);
+ auth_type = RPCAUTH_KERB4;
+ bzero((caddr_t)key, sizeof (key));
+ if (failed_auth || nfs_getnickauth(nmp, cred, &auth_str,
+ &auth_len, verf_str, verf_len)) {
+ error = nfs_getauth(nmp, rep, cred, &auth_str,
+ &auth_len, verf_str, &verf_len, key);
if (error) {
free((caddr_t)rep, M_NFSREQ);
m_freem(mrest);
return (error);
}
- } else {
- auth_type = RPCAUTH_UNIX;
- auth_len = 5 * NFSX_UNSIGNED;
}
} else {
auth_type = RPCAUTH_UNIX;
@@ -922,8 +912,8 @@ kerbauth:
nmp->nm_numgrps : (cred->cr_ngroups - 1)) << 2) +
5 * NFSX_UNSIGNED;
}
- m = nfsm_rpchead(cred, (nmp->nm_flag & NFSMNT_NQNFS), procnum,
- auth_type, auth_len, auth_str, mrest, mrest_len, &mheadend, &xid);
+ m = nfsm_rpchead(cred, nmp->nm_flag, procnum, auth_type, auth_len,
+ auth_str, verf_len, verf_str, mrest, mrest_len, &mheadend, &xid);
if (auth_str)
free(auth_str, M_TEMP);
@@ -1029,12 +1019,12 @@ tryagain:
/*
* break down the rpc header and check if ok
*/
- nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
if (*tl++ == rpc_msgdenied) {
if (*tl == rpc_mismatch)
error = EOPNOTSUPP;
else if ((nmp->nm_flag & NFSMNT_KERB) && *tl++ == rpc_autherr) {
- if (*tl == rpc_rejectedcred && failed_auth == 0) {
+ if (!failed_auth) {
failed_auth++;
mheadend->m_next = (struct mbuf *)0;
m_freem(mrep);
@@ -1051,22 +1041,25 @@ tryagain:
}
/*
- * skip over the auth_verf, someday we may want to cache auth_short's
- * for nfs_reqhead(), but for now just dump it
+ * Grab any Kerberos verifier, otherwise just throw it away.
*/
- if (*++tl != 0) {
- i = nfsm_rndup(fxdr_unsigned(long, *tl));
- nfsm_adv(i);
- }
+ verf_type = fxdr_unsigned(int, *tl++);
+ i = fxdr_unsigned(int, *tl);
+ if ((nmp->nm_flag & NFSMNT_KERB) && verf_type == RPCAUTH_KERB4) {
+ error = nfs_savenickauth(nmp, cred, i, key, &md, &dpos, mrep);
+ if (error)
+ goto nfsmout;
+ } else if (i > 0)
+ nfsm_adv(nfsm_rndup(i));
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
/* 0 == ok */
if (*tl == 0) {
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
if (*tl != 0) {
error = fxdr_unsigned(int, *tl);
- m_freem(mrep);
- if ((nmp->nm_flag & NFSMNT_NQNFS) &&
- error == NQNFS_TRYLATER) {
+ if ((nmp->nm_flag & NFSMNT_NFSV3) &&
+ error == NFSERR_TRYLATER) {
+ m_freem(mrep);
error = 0;
waituntil = time.tv_sec + trylater_delay;
while (time.tv_sec < waituntil)
@@ -1084,6 +1077,13 @@ tryagain:
*/
if (error == ESTALE)
cache_purge(vp);
+ if (nmp->nm_flag & NFSMNT_NFSV3) {
+ *mrp = mrep;
+ *mdp = md;
+ *dposp = dpos;
+ error |= NFSERR_RETERR;
+ } else
+ m_freem(mrep);
m_freem(rep->r_mreq);
free((caddr_t)rep, M_NFSREQ);
return (error);
@@ -1115,10 +1115,10 @@ tryagain:
return (0);
}
m_freem(mrep);
- m_freem(rep->r_mreq);
- free((caddr_t)rep, M_NFSREQ);
error = EPROTONOSUPPORT;
nfsmout:
+ m_freem(rep->r_mreq);
+ free((caddr_t)rep, M_NFSREQ);
return (error);
}
@@ -1127,9 +1127,10 @@ nfsmout:
* siz arg. is used to decide if adding a cluster is worthwhile
*/
int
-nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp)
+nfs_rephead(siz, nd, slp, err, cache, frev, mrq, mbp, bposp)
int siz;
- struct nfsd *nd;
+ struct nfsrv_descript *nd;
+ struct nfssvc_sock *slp;
int err;
int cache;
u_quad_t *frev;
@@ -1154,47 +1155,98 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp)
} else
mreq->m_data += max_hdr;
tl = mtod(mreq, u_long *);
- mreq->m_len = 6*NFSX_UNSIGNED;
- bpos = ((caddr_t)tl)+mreq->m_len;
+ mreq->m_len = 6 * NFSX_UNSIGNED;
+ bpos = ((caddr_t)tl) + mreq->m_len;
*tl++ = txdr_unsigned(nd->nd_retxid);
*tl++ = rpc_reply;
- if (err == ERPCMISMATCH || err == NQNFS_AUTHERR) {
+ if (err == ERPCMISMATCH || (err & NFSERR_AUTHERR)) {
*tl++ = rpc_msgdenied;
- if (err == NQNFS_AUTHERR) {
+ if (err & NFSERR_AUTHERR) {
*tl++ = rpc_autherr;
- *tl = rpc_rejectedcred;
+ *tl = txdr_unsigned(err & ~NFSERR_AUTHERR);
mreq->m_len -= NFSX_UNSIGNED;
bpos -= NFSX_UNSIGNED;
} else {
*tl++ = rpc_mismatch;
- *tl++ = txdr_unsigned(2);
- *tl = txdr_unsigned(2);
+ *tl++ = txdr_unsigned(RPC_VER2);
+ *tl = txdr_unsigned(RPC_VER2);
}
} else {
*tl++ = rpc_msgaccepted;
- *tl++ = 0;
- *tl++ = 0;
+
+ /*
+ * For Kerberos authentication, we must send the nickname
+ * verifier back, otherwise just RPCAUTH_NULL.
+ */
+ if (nd->nd_flag & ND_KERBFULL) {
+ register struct nfsuid *nuidp;
+ struct timeval ktvin, ktvout;
+ NFSKERBKEYSCHED_T keys; /* stores key schedule */
+
+ for (nuidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first;
+ nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
+ if (nuidp->nu_cr.cr_uid == nd->nd_cr.cr_uid &&
+ (!nd->nd_nam2 || netaddr_match(NU_NETFAM(nuidp),
+ &nuidp->nu_haddr, nd->nd_nam2)))
+ break;
+ }
+ if (nuidp) {
+ ktvin.tv_sec =
+ txdr_unsigned(nuidp->nu_timestamp.tv_sec - 1);
+ ktvin.tv_usec =
+ txdr_unsigned(nuidp->nu_timestamp.tv_usec);
+
+ /*
+ * Encrypt the timestamp in ecb mode using the
+ * session key.
+ */
+#ifdef NFSKERB
+ XXX
+#endif
+
+ *tl++ = rpc_auth_kerb;
+ *tl++ = txdr_unsigned(3 * NFSX_UNSIGNED);
+ *tl = ktvout.tv_sec;
+ nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ *tl++ = ktvout.tv_usec;
+ *tl++ = txdr_unsigned(nuidp->nu_cr.cr_uid);
+ } else {
+ *tl++ = 0;
+ *tl++ = 0;
+ }
+ } else {
+ *tl++ = 0;
+ *tl++ = 0;
+ }
switch (err) {
case EPROGUNAVAIL:
*tl = txdr_unsigned(RPC_PROGUNAVAIL);
break;
case EPROGMISMATCH:
*tl = txdr_unsigned(RPC_PROGMISMATCH);
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(2);
- *tl = txdr_unsigned(2); /* someday 3 */
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ if (nd->nd_flag & ND_NQNFS) {
+ *tl++ = txdr_unsigned(3);
+ *tl = txdr_unsigned(3);
+ } else {
+ *tl++ = txdr_unsigned(2);
+ *tl = txdr_unsigned(3);
+ }
break;
case EPROCUNAVAIL:
*tl = txdr_unsigned(RPC_PROCUNAVAIL);
break;
+ case EBADRPC:
+ *tl = txdr_unsigned(RPC_GARBAGE);
+ break;
default:
*tl = 0;
- if (err != VNOVAL) {
+ if (err != NFSERR_RETVOID) {
nfsm_build(tl, u_long *, NFSX_UNSIGNED);
if (err)
- *tl = txdr_unsigned(nfsrv_errmap[err - 1]);
+ *tl = txdr_unsigned(nfsrv_errmap(nd, err));
else
- *tl = 0;
+ *tl = 0;
}
break;
};
@@ -1203,16 +1255,14 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp)
/*
* For nqnfs, piggyback lease as requested.
*/
- if (nd->nd_nqlflag != NQL_NOVAL && err == 0) {
- if (nd->nd_nqlflag) {
- nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(nd->nd_nqlflag);
+ if ((nd->nd_flag & ND_NQNFS) && err == 0) {
+ if (nd->nd_flag & ND_LEASE) {
+ nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
+ *tl++ = txdr_unsigned(nd->nd_flag & ND_LEASE);
*tl++ = txdr_unsigned(cache);
*tl++ = txdr_unsigned(nd->nd_duration);
txdr_hyper(frev, tl);
} else {
- if (nd->nd_nqlflag != 0)
- panic("nqreph");
nfsm_build(tl, u_long *, NFSX_UNSIGNED);
*tl = 0;
}
@@ -1220,7 +1270,7 @@ nfs_rephead(siz, nd, err, cache, frev, mrq, mbp, bposp)
*mrq = mreq;
*mbp = mb;
*bposp = bpos;
- if (err != 0 && err != VNOVAL)
+ if (err != 0 && err != NFSERR_RETVOID)
nfsstats.srvrpc_errs++;
return (0);
}
@@ -1240,8 +1290,10 @@ nfs_timer(arg)
register struct socket *so;
register struct nfsmount *nmp;
register int timeo;
+ register struct nfssvc_sock *slp;
static long lasttime = 0;
int s, error;
+ u_quad_t cur_usec;
s = splnet();
for (rep = nfs_reqq.tqh_first; rep != 0; rep = rep->r_chain.tqe_next) {
@@ -1338,8 +1390,19 @@ nfs_timer(arg)
lasttime = time.tv_sec;
nqnfs_serverd();
}
+
+ /*
+ * Scan the write gathering queues for writes that need to be
+ * completed now.
+ */
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
+ for (slp = nfssvc_sockhead.tqh_first; slp != 0;
+ slp = slp->ns_chain.tqe_next) {
+ if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec)
+ nfsrv_wakenfsd(slp);
+ }
splx(s);
- timeout(nfs_timer, (void *)0, hz / NFS_HZ);
+ timeout(nfs_timer, (void *)0, nfs_ticks);
}
/*
@@ -1673,7 +1736,7 @@ nfsrv_getstream(slp, waitflag)
register struct nfssvc_sock *slp;
int waitflag;
{
- register struct mbuf *m;
+ register struct mbuf *m, **mpp;
register char *cp1, *cp2;
register int len;
struct mbuf *om, *m2, *recm = 0;
@@ -1707,7 +1770,12 @@ nfsrv_getstream(slp, waitflag)
}
}
slp->ns_cc -= NFSX_UNSIGNED;
- slp->ns_reclen = ntohl(recmark) & ~0x80000000;
+ recmark = ntohl(recmark);
+ slp->ns_reclen = recmark & ~0x80000000;
+ if (recmark & 0x80000000)
+ slp->ns_flag |= SLP_LASTFRAG;
+ else
+ slp->ns_flag &= ~SLP_LASTFRAG;
if (slp->ns_reclen < NFS_MINPACKET || slp->ns_reclen > NFS_MAXPACKET) {
slp->ns_flag &= ~SLP_GETSTREAM;
return (EPERM);
@@ -1761,12 +1829,23 @@ nfsrv_getstream(slp, waitflag)
slp->ns_flag &= ~SLP_GETSTREAM;
return (0);
}
- nfs_realign(recm, 10 * NFSX_UNSIGNED);
- if (slp->ns_recend)
- slp->ns_recend->m_nextpkt = recm;
- else
- slp->ns_rec = recm;
- slp->ns_recend = recm;
+
+ /*
+ * Accumulate the fragments into a record.
+ */
+ mpp = &slp->ns_frag;
+ while (*mpp)
+ mpp = &((*mpp)->m_next);
+ *mpp = recm;
+ if (slp->ns_flag & SLP_LASTFRAG) {
+ nfs_realign(slp->ns_frag, 10 * NFSX_UNSIGNED);
+ if (slp->ns_recend)
+ slp->ns_recend->m_nextpkt = slp->ns_frag;
+ else
+ slp->ns_rec = slp->ns_frag;
+ slp->ns_recend = slp->ns_frag;
+ slp->ns_frag = (struct mbuf *)0;
+ }
}
}
@@ -1774,13 +1853,16 @@ nfsrv_getstream(slp, waitflag)
* Parse an RPC header.
*/
int
-nfsrv_dorec(slp, nd)
+nfsrv_dorec(slp, nfsd, ndp)
register struct nfssvc_sock *slp;
- register struct nfsd *nd;
+ struct nfsd *nfsd;
+ struct nfsrv_descript **ndp;
{
- register struct mbuf *m;
+ register struct mbuf *m, *nam;
+ register struct nfsrv_descript *nd;
int error;
+ *ndp = NULL;
if ((slp->ns_flag & SLP_VALID) == 0 ||
(m = slp->ns_rec) == (struct mbuf *)0)
return (ENOBUFS);
@@ -1790,19 +1872,24 @@ nfsrv_dorec(slp, nd)
else
slp->ns_recend = (struct mbuf *)0;
if (m->m_type == MT_SONAME) {
- nd->nd_nam = m;
- nd->nd_md = nd->nd_mrep = m->m_next;
- m->m_next = (struct mbuf *)0;
- } else {
- nd->nd_nam = (struct mbuf *)0;
- nd->nd_md = nd->nd_mrep = m;
- }
- nd->nd_dpos = mtod(nd->nd_md, caddr_t);
- error = nfs_getreq(nd, TRUE);
+ nam = m;
+ m = m->m_next;
+ nam->m_next = NULL;
+ } else
+ nam = NULL;
+ MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript),
+ M_NFSRVDESC, M_WAITOK);
+ nd->nd_md = nd->nd_mrep = m;
+ nd->nd_nam2 = nam;
+ nd->nd_dpos = mtod(m, caddr_t);
+ error = nfs_getreq(nd, nfsd, TRUE);
if (error) {
- m_freem(nd->nd_nam);
+ m_freem(nam);
+ free((caddr_t)nd, M_NFSRVDESC);
return (error);
}
+ *ndp = nd;
+ nfsd->nfsd_nd = nd;
return (0);
}
@@ -1812,8 +1899,9 @@ nfsrv_dorec(slp, nd)
* - fill in the cred struct.
*/
int
-nfs_getreq(nd, has_header)
- register struct nfsd *nd;
+nfs_getreq(nd, nfsd, has_header)
+ register struct nfsrv_descript *nd;
+ struct nfsd *nfsd;
int has_header;
{
register int len, i;
@@ -1821,57 +1909,67 @@ nfs_getreq(nd, has_header)
register long t1;
struct uio uio;
struct iovec iov;
- caddr_t dpos, cp2;
+ caddr_t dpos, cp2, cp;
u_long nfsvers, auth_type;
- int error = 0, nqnfs = 0;
+ uid_t nickuid;
+ int error = 0, nqnfs = 0, ticklen;
struct mbuf *mrep, *md;
+ register struct nfsuid *nuidp;
+ struct timeval tvin, tvout;
+ NFSKERBKEYSCHED_T keys; /* stores key schedule */
mrep = nd->nd_mrep;
md = nd->nd_md;
dpos = nd->nd_dpos;
if (has_header) {
- nfsm_dissect(tl, u_long *, 10*NFSX_UNSIGNED);
+ nfsm_dissect(tl, u_long *, 10 * NFSX_UNSIGNED);
nd->nd_retxid = fxdr_unsigned(u_long, *tl++);
if (*tl++ != rpc_call) {
m_freem(mrep);
return (EBADRPC);
}
- } else {
- nfsm_dissect(tl, u_long *, 8*NFSX_UNSIGNED);
- }
+ } else
+ nfsm_dissect(tl, u_long *, 8 * NFSX_UNSIGNED);
nd->nd_repstat = 0;
+ nd->nd_flag = 0;
if (*tl++ != rpc_vers) {
nd->nd_repstat = ERPCMISMATCH;
nd->nd_procnum = NFSPROC_NOOP;
return (0);
}
- nfsvers = nfs_vers;
if (*tl != nfs_prog) {
- if (*tl == nqnfs_prog) {
+ if (*tl == nqnfs_prog)
nqnfs++;
- nfsvers = nqnfs_vers;
- } else {
+ else {
nd->nd_repstat = EPROGUNAVAIL;
nd->nd_procnum = NFSPROC_NOOP;
return (0);
}
}
tl++;
- if (*tl++ != nfsvers) {
+ nfsvers = fxdr_unsigned(u_long, *tl++);
+ if (((nfsvers < NFS_VER2 || nfsvers > NFS_VER3) && !nqnfs) ||
+ (nfsvers != NQNFS_VER3 && nqnfs)) {
nd->nd_repstat = EPROGMISMATCH;
nd->nd_procnum = NFSPROC_NOOP;
return (0);
}
+ if (nqnfs)
+ nd->nd_flag = (ND_NFSV3 | ND_NQNFS);
+ else if (nfsvers == NFS_VER3)
+ nd->nd_flag = ND_NFSV3;
nd->nd_procnum = fxdr_unsigned(u_long, *tl++);
if (nd->nd_procnum == NFSPROC_NULL)
return (0);
if (nd->nd_procnum >= NFS_NPROCS ||
- (!nqnfs && nd->nd_procnum > NFSPROC_STATFS) ||
- (*tl != rpc_auth_unix && *tl != rpc_auth_kerb)) {
+ (!nqnfs && nd->nd_procnum >= NQNFSPROC_GETLEASE) ||
+ (!nd->nd_flag && nd->nd_procnum > NFSV2PROC_STATFS)) {
nd->nd_repstat = EPROCUNAVAIL;
nd->nd_procnum = NFSPROC_NOOP;
return (0);
}
+ if ((nd->nd_flag & ND_NFSV3) == 0)
+ nd->nd_procnum = nfsv3_procid[nd->nd_procnum];
auth_type = *tl++;
len = fxdr_unsigned(int, *tl++);
if (len < 0 || len > RPCAUTH_MAXSIZ) {
@@ -1879,6 +1977,7 @@ nfs_getreq(nd, has_header)
return (EBADRPC);
}
+ nd->nd_flag &= ~ND_KERBAUTH;
/*
* Handle auth_unix or auth_kerb.
*/
@@ -1889,7 +1988,9 @@ nfs_getreq(nd, has_header)
return (EBADRPC);
}
nfsm_adv(nfsm_rndup(len));
- nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ bzero((caddr_t)&nd->nd_cr, sizeof (struct ucred));
+ nd->nd_cr.cr_ref = 1;
nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
nd->nd_cr.cr_gid = fxdr_unsigned(gid_t, *tl++);
len = fxdr_unsigned(int, *tl);
@@ -1897,45 +1998,124 @@ nfs_getreq(nd, has_header)
m_freem(mrep);
return (EBADRPC);
}
- nfsm_dissect(tl, u_long *, (len + 2)*NFSX_UNSIGNED);
+ nfsm_dissect(tl, u_long *, (len + 2) * NFSX_UNSIGNED);
for (i = 1; i <= len; i++)
- if (i < NGROUPS)
- nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
- else
- tl++;
+ if (i < NGROUPS)
+ nd->nd_cr.cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
+ else
+ tl++;
nd->nd_cr.cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
- } else if (auth_type == rpc_auth_kerb) {
- nd->nd_cr.cr_uid = fxdr_unsigned(uid_t, *tl++);
- nd->nd_authlen = fxdr_unsigned(int, *tl);
- uio.uio_resid = nfsm_rndup(nd->nd_authlen);
- if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
+ if (nd->nd_cr.cr_ngroups > 1)
+ nfsrvw_sort(nd->nd_cr.cr_groups, nd->nd_cr.cr_ngroups);
+ len = fxdr_unsigned(int, *++tl);
+ if (len < 0 || len > RPCAUTH_MAXSIZ) {
m_freem(mrep);
return (EBADRPC);
}
- uio.uio_offset = 0;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_segflg = UIO_SYSSPACE;
- iov.iov_base = (caddr_t)nd->nd_authstr;
- iov.iov_len = RPCAUTH_MAXSIZ;
- nfsm_mtouio(&uio, uio.uio_resid);
- nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
- nd->nd_flag |= NFSD_NEEDAUTH;
- }
+ if (len > 0)
+ nfsm_adv(nfsm_rndup(len));
+ } else if (auth_type == rpc_auth_kerb) {
+ switch (fxdr_unsigned(int, *tl++)) {
+ case RPCAKN_FULLNAME:
+ ticklen = fxdr_unsigned(int, *tl);
+ *((u_long *)nfsd->nfsd_authstr) = *tl;
+ uio.uio_resid = nfsm_rndup(ticklen) + NFSX_UNSIGNED;
+ nfsd->nfsd_authlen = uio.uio_resid + NFSX_UNSIGNED;
+ if (uio.uio_resid > (len - 2 * NFSX_UNSIGNED)) {
+ m_freem(mrep);
+ return (EBADRPC);
+ }
+ uio.uio_offset = 0;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_segflg = UIO_SYSSPACE;
+ iov.iov_base = (caddr_t)&nfsd->nfsd_authstr[4];
+ iov.iov_len = RPCAUTH_MAXSIZ - 4;
+ nfsm_mtouio(&uio, uio.uio_resid);
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ if (*tl++ != rpc_auth_kerb ||
+ fxdr_unsigned(int, *tl) != 4 * NFSX_UNSIGNED) {
+ printf("Bad kerb verifier\n");
+ nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
+ }
+ nfsm_dissect(cp, caddr_t, 4 * NFSX_UNSIGNED);
+ tl = (u_long *)cp;
+ if (fxdr_unsigned(int, *tl) != RPCAKN_FULLNAME) {
+ printf("Not fullname kerb verifier\n");
+ nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
+ }
+ cp += NFSX_UNSIGNED;
+ bcopy(cp, nfsd->nfsd_verfstr, 3 * NFSX_UNSIGNED);
+ nfsd->nfsd_verflen = 3 * NFSX_UNSIGNED;
+ nd->nd_flag |= ND_KERBFULL;
+ nfsd->nfsd_flag |= NFSD_NEEDAUTH;
+ break;
+ case RPCAKN_NICKNAME:
+ if (len != 2 * NFSX_UNSIGNED) {
+ printf("Kerb nickname short\n");
+ nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADCRED);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
+ }
+ nickuid = fxdr_unsigned(uid_t, *tl);
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ if (*tl++ != rpc_auth_kerb ||
+ fxdr_unsigned(int, *tl) != 3 * NFSX_UNSIGNED) {
+ printf("Kerb nick verifier bad\n");
+ nd->nd_repstat = (NFSERR_AUTHERR|AUTH_BADVERF);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
+ }
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ tvin.tv_sec = *tl++;
+ tvin.tv_usec = *tl;
+
+ for (nuidp = NUIDHASH(nfsd->nfsd_slp,nickuid)->lh_first;
+ nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
+ if (nuidp->nu_cr.cr_uid == nickuid &&
+ (!nd->nd_nam2 ||
+ netaddr_match(NU_NETFAM(nuidp),
+ &nuidp->nu_haddr, nd->nd_nam2)))
+ break;
+ }
+ if (!nuidp) {
+ nd->nd_repstat =
+ (NFSERR_AUTHERR|AUTH_REJECTCRED);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
+ }
- /*
- * Do we have any use for the verifier.
- * According to the "Remote Procedure Call Protocol Spec." it
- * should be AUTH_NULL, but some clients make it AUTH_UNIX?
- * For now, just skip over it
- */
- len = fxdr_unsigned(int, *++tl);
- if (len < 0 || len > RPCAUTH_MAXSIZ) {
- m_freem(mrep);
- return (EBADRPC);
- }
- if (len > 0) {
- nfsm_adv(nfsm_rndup(len));
+ /*
+ * Now, decrypt the timestamp using the session key
+ * and validate it.
+ */
+#ifdef NFSKERB
+ XXX
+#endif
+
+ tvout.tv_sec = fxdr_unsigned(long, tvout.tv_sec);
+ tvout.tv_usec = fxdr_unsigned(long, tvout.tv_usec);
+ if (nuidp->nu_expire < time.tv_sec ||
+ nuidp->nu_timestamp.tv_sec > tvout.tv_sec ||
+ (nuidp->nu_timestamp.tv_sec == tvout.tv_sec &&
+ nuidp->nu_timestamp.tv_usec > tvout.tv_usec)) {
+ nuidp->nu_expire = 0;
+ nd->nd_repstat =
+ (NFSERR_AUTHERR|AUTH_REJECTVERF);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
+ }
+ nfsrv_setcred(&nuidp->nu_cr, &nd->nd_cr);
+ nd->nd_flag |= ND_KERBNICK;
+ };
+ } else {
+ nd->nd_repstat = (NFSERR_AUTHERR | AUTH_REJECTCRED);
+ nd->nd_procnum = NFSPROC_NOOP;
+ return (0);
}
/*
@@ -1943,16 +2123,14 @@ nfs_getreq(nd, has_header)
*/
if (nqnfs && nd->nd_procnum != NQNFSPROC_EVICTED) {
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
- nd->nd_nqlflag = fxdr_unsigned(int, *tl);
- if (nd->nd_nqlflag) {
+ nd->nd_flag |= fxdr_unsigned(int, *tl);
+ if (nd->nd_flag & ND_LEASE) {
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
nd->nd_duration = fxdr_unsigned(int, *tl);
} else
nd->nd_duration = NQ_MINLEASE;
- } else {
- nd->nd_nqlflag = NQL_NOVAL;
+ } else
nd->nd_duration = NQ_MINLEASE;
- }
nd->nd_md = md;
nd->nd_dpos = dpos;
return (0);
@@ -1973,13 +2151,13 @@ nfsrv_wakenfsd(slp)
if ((slp->ns_flag & SLP_VALID) == 0)
return;
- for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nd_chain.tqe_next) {
- if (nd->nd_flag & NFSD_WAITING) {
- nd->nd_flag &= ~NFSD_WAITING;
- if (nd->nd_slp)
+ for (nd = nfsd_head.tqh_first; nd != 0; nd = nd->nfsd_chain.tqe_next) {
+ if (nd->nfsd_flag & NFSD_WAITING) {
+ nd->nfsd_flag &= ~NFSD_WAITING;
+ if (nd->nfsd_slp)
panic("nfsd wakeup");
slp->ns_sref++;
- nd->nd_slp = slp;
+ nd->nfsd_slp = slp;
wakeup((caddr_t)nd);
return;
}
diff --git a/sys/nfs/nfs_srvcache.c b/sys/nfs/nfs_srvcache.c
index 0f31ae08a4ae..acdce0dcc605 100644
--- a/sys/nfs/nfs_srvcache.c
+++ b/sys/nfs/nfs_srvcache.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_srvcache.c 8.1 (Berkeley) 6/10/93
- * $Id: nfs_srvcache.c,v 1.4 1994/10/02 17:27:00 phk Exp $
+ * $Id: nfs_srvcache.c,v 1.5 1994/10/17 17:47:36 phk Exp $
*/
/*
@@ -59,11 +59,13 @@
#endif
#include <nfs/nfsm_subs.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsrvcache.h>
#include <nfs/nqnfs.h>
+extern struct nfsstats nfsstats;
+extern int nfsv2_procid[NFS_NPROCS];
long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
#define NFSRCHASH(xid) \
@@ -89,7 +91,6 @@ int nonidempotent[NFS_NPROCS] = {
FALSE,
FALSE,
FALSE,
- FALSE,
TRUE,
TRUE,
TRUE,
@@ -98,6 +99,10 @@ int nonidempotent[NFS_NPROCS] = {
TRUE,
TRUE,
TRUE,
+ TRUE,
+ FALSE,
+ FALSE,
+ FALSE,
FALSE,
FALSE,
FALSE,
@@ -108,7 +113,7 @@ int nonidempotent[NFS_NPROCS] = {
};
/* True iff the rpc reply is an nfs status ONLY! */
-static int repliesstatus[NFS_NPROCS] = {
+static int nfsv2_repstat[NFS_NPROCS] = {
FALSE,
FALSE,
FALSE,
@@ -127,11 +132,6 @@ static int repliesstatus[NFS_NPROCS] = {
TRUE,
FALSE,
FALSE,
- FALSE,
- FALSE,
- FALSE,
- FALSE,
- TRUE,
};
/*
@@ -160,9 +160,9 @@ nfsrv_initcache()
* Update/add new request at end of lru list
*/
int
-nfsrv_getcache(nam, nd, repp)
- struct mbuf *nam;
- register struct nfsd *nd;
+nfsrv_getcache(nd, slp, repp)
+ register struct nfsrv_descript *nd;
+ struct nfssvc_sock *slp;
struct mbuf **repp;
{
register struct nfsrvcache *rp;
@@ -171,13 +171,17 @@ nfsrv_getcache(nam, nd, repp)
caddr_t bpos;
int ret;
- if (nd->nd_nqlflag != NQL_NOVAL)
+ /*
+ * Don't cache recent requests for reliable transport protocols.
+ * (Maybe we should for the case of a reconnect, but..)
+ */
+ if (!nd->nd_nam2)
return (RC_DOIT);
loop:
for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
rp = rp->rc_hash.le_next) {
if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
- netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) {
+ netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
if ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
@@ -196,7 +200,7 @@ loop:
ret = RC_DROPIT;
} else if (rp->rc_flag & RC_REPSTATUS) {
nfsstats.srvcache_nonidemdonehits++;
- nfs_rephead(0, nd, rp->rc_status,
+ nfs_rephead(0, nd, slp, rp->rc_status,
0, (u_quad_t *)0, repp, &mb, &bpos);
ret = RC_REPLY;
} else if (rp->rc_flag & RC_REPMBUF) {
@@ -243,7 +247,7 @@ loop:
TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
rp->rc_state = RC_INPROG;
rp->rc_xid = nd->nd_retxid;
- saddr = mtod(nam, struct sockaddr_in *);
+ saddr = mtod(nd->nd_nam, struct sockaddr_in *);
switch (saddr->sin_family) {
case AF_INET:
rp->rc_flag |= RC_INETADDR;
@@ -252,7 +256,7 @@ loop:
case AF_ISO:
default:
rp->rc_flag |= RC_NAM;
- rp->rc_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
+ rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT);
break;
};
rp->rc_proc = nd->nd_procnum;
@@ -269,21 +273,20 @@ loop:
* Update a request cache entry after the rpc has been done
*/
void
-nfsrv_updatecache(nam, nd, repvalid, repmbuf)
- struct mbuf *nam;
- register struct nfsd *nd;
+nfsrv_updatecache(nd, repvalid, repmbuf)
+ register struct nfsrv_descript *nd;
int repvalid;
struct mbuf *repmbuf;
{
register struct nfsrvcache *rp;
- if (nd->nd_nqlflag != NQL_NOVAL)
+ if (!nd->nd_nam2)
return;
loop:
for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
rp = rp->rc_hash.le_next) {
if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
- netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) {
+ netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
if ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
@@ -296,7 +299,8 @@ loop:
* the reply for non-idempotent rpc's.
*/
if (repvalid && nonidempotent[nd->nd_procnum]) {
- if (repliesstatus[nd->nd_procnum]) {
+ if ((nd->nd_flag & ND_NFSV3) == 0 &&
+ nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) {
rp->rc_status = nd->nd_repstat;
rp->rc_flag |= RC_REPSTATUS;
} else {
diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c
index 1653c8b4cb3d..350ba469d289 100644
--- a/sys/nfs/nfs_subs.c
+++ b/sys/nfs/nfs_subs.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94
- * $Id: nfs_subs.c,v 1.15 1995/05/30 08:12:43 rgrimes Exp $
+ * $Id: nfs_subs.c,v 1.16 1995/06/14 06:23:38 joerg Exp $
*/
/*
@@ -52,6 +52,7 @@
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/malloc.h>
#ifdef VFS_LKM
#include <sys/sysent.h>
#include <sys/syscall.h>
@@ -60,7 +61,7 @@
#include <vm/vm.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfsnode.h>
#include <nfs/nfs.h>
#include <nfs/xdr_subs.h>
@@ -78,31 +79,455 @@
#include <netiso/iso.h>
#endif
-#define TRUE 1
-#define FALSE 0
-
/*
* Data items converted to xdr at startup, since they are constant
* This is kinda hokey, but may save a little time doing byte swaps
*/
-u_long nfs_procids[NFS_NPROCS];
u_long nfs_xdrneg1;
u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
- rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
+ rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
rpc_auth_kerb;
-u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
+u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
/* And other global data */
static u_long nfs_xid = 0;
-enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
+enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
+enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
+int nfs_ticks;
+
+/*
+ * Mapping of old NFS Version 2 RPC numbers to generic numbers.
+ */
+int nfsv3_procid[NFS_NPROCS] = {
+ NFSPROC_NULL,
+ NFSPROC_GETATTR,
+ NFSPROC_SETATTR,
+ NFSPROC_NOOP,
+ NFSPROC_LOOKUP,
+ NFSPROC_READLINK,
+ NFSPROC_READ,
+ NFSPROC_NOOP,
+ NFSPROC_WRITE,
+ NFSPROC_CREATE,
+ NFSPROC_REMOVE,
+ NFSPROC_RENAME,
+ NFSPROC_LINK,
+ NFSPROC_SYMLINK,
+ NFSPROC_MKDIR,
+ NFSPROC_RMDIR,
+ NFSPROC_READDIR,
+ NFSPROC_FSSTAT,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP,
+ NFSPROC_NOOP
+};
+
+/*
+ * and the reverse mapping from generic to Version 2 procedure numbers
+ */
+int nfsv2_procid[NFS_NPROCS] = {
+ NFSV2PROC_NULL,
+ NFSV2PROC_GETATTR,
+ NFSV2PROC_SETATTR,
+ NFSV2PROC_LOOKUP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_READLINK,
+ NFSV2PROC_READ,
+ NFSV2PROC_WRITE,
+ NFSV2PROC_CREATE,
+ NFSV2PROC_MKDIR,
+ NFSV2PROC_SYMLINK,
+ NFSV2PROC_CREATE,
+ NFSV2PROC_REMOVE,
+ NFSV2PROC_RMDIR,
+ NFSV2PROC_RENAME,
+ NFSV2PROC_LINK,
+ NFSV2PROC_READDIR,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_STATFS,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+ NFSV2PROC_NOOP,
+};
+
+/*
+ * Maps errno values to nfs error numbers.
+ * Use NFSERR_IO as the catch all for ones not specifically defined in
+ * RFC 1094.
+ */
+static u_char nfsrv_v2errmap[ELAST] = {
+ NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
+ NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
+ NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO,
+};
+
+/*
+ * Maps errno values to nfs error numbers.
+ * Although it is not obvious whether or not NFS clients really care if
+ * a returned error value is in the specified list for the procedure, the
+ * safest thing to do is filter them appropriately. For Version 2, the
+ * X/Open XNFS document is the only specification that defines error values
+ * for each RPC (The RFC simply lists all possible error values for all RPCs),
+ * so I have decided to not do this for Version 2.
+ * The first entry is the default error return and the rest are the valid
+ * errors for that RPC in increasing numeric order.
+ */
+static short nfsv3err_null[] = {
+ 0,
+ 0,
+};
+
+static short nfsv3err_getattr[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_setattr[] = {
+ NFSERR_IO,
+ NFSERR_PERM,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOT_SYNC,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_lookup[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_NAMETOL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_access[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_readlink[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_read[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_NXIO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_write[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_INVAL,
+ NFSERR_FBIG,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_create[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_mkdir[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_symlink[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_mknod[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ NFSERR_BADTYPE,
+ 0,
+};
+
+static short nfsv3err_remove[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_rmdir[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_NOTDIR,
+ NFSERR_INVAL,
+ NFSERR_ROFS,
+ NFSERR_NAMETOL,
+ NFSERR_NOTEMPTY,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_rename[] = {
+ NFSERR_IO,
+ NFSERR_NOENT,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_XDEV,
+ NFSERR_NOTDIR,
+ NFSERR_ISDIR,
+ NFSERR_INVAL,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_MLINK,
+ NFSERR_NAMETOL,
+ NFSERR_NOTEMPTY,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_link[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_EXIST,
+ NFSERR_XDEV,
+ NFSERR_NOTDIR,
+ NFSERR_INVAL,
+ NFSERR_NOSPC,
+ NFSERR_ROFS,
+ NFSERR_MLINK,
+ NFSERR_NAMETOL,
+ NFSERR_DQUOT,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_NOTSUPP,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_readdir[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_BAD_COOKIE,
+ NFSERR_TOOSMALL,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_readdirplus[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_ACCES,
+ NFSERR_NOTDIR,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_BAD_COOKIE,
+ NFSERR_NOTSUPP,
+ NFSERR_TOOSMALL,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_fsstat[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_fsinfo[] = {
+ NFSERR_STALE,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_pathconf[] = {
+ NFSERR_STALE,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short nfsv3err_commit[] = {
+ NFSERR_IO,
+ NFSERR_IO,
+ NFSERR_STALE,
+ NFSERR_BADHANDLE,
+ NFSERR_SERVERFAULT,
+ 0,
+};
+
+static short *nfsrv_v3errmap[] = {
+ nfsv3err_null,
+ nfsv3err_getattr,
+ nfsv3err_setattr,
+ nfsv3err_lookup,
+ nfsv3err_access,
+ nfsv3err_readlink,
+ nfsv3err_read,
+ nfsv3err_write,
+ nfsv3err_create,
+ nfsv3err_mkdir,
+ nfsv3err_symlink,
+ nfsv3err_mknod,
+ nfsv3err_remove,
+ nfsv3err_rmdir,
+ nfsv3err_rename,
+ nfsv3err_link,
+ nfsv3err_readdir,
+ nfsv3err_readdirplus,
+ nfsv3err_fsstat,
+ nfsv3err_fsinfo,
+ nfsv3err_pathconf,
+ nfsv3err_commit,
+};
+
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
-extern int nqnfs_piggy[NFS_NPROCS];
extern struct nfsrtt nfsrtt;
extern time_t nqnfsstarttime;
-extern u_long nqnfs_prog, nqnfs_vers;
extern int nqsrv_clockskew;
extern int nqsrv_writeslack;
extern int nqsrv_maxlease;
+extern struct nfsstats nfsstats;
+extern int nqnfs_piggy[NFS_NPROCS];
+extern nfstype nfsv2_type[9];
+extern nfstype nfsv3_type[9];
+extern struct nfsnodehashhead *nfsnodehashtbl;
+extern u_long nfsnodehash;
#ifdef VFS_LKM
struct getfh_args;
@@ -167,14 +592,16 @@ nfsm_reqh(vp, procid, hsiz, bposp)
* Returns the head of the mbuf list.
*/
struct mbuf *
-nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
- mrest_len, mbp, xidp)
+nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
+ verf_str, mrest, mrest_len, mbp, xidp)
register struct ucred *cr;
- int nqnfs;
+ int nmflag;
int procid;
int auth_type;
int auth_len;
char *auth_str;
+ int verf_len;
+ char *verf_str;
struct mbuf *mrest;
int mrest_len;
struct mbuf **mbp;
@@ -188,15 +615,13 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
int siz, grpsiz, authsiz;
authsiz = nfsm_rndup(auth_len);
- if (auth_type == RPCAUTH_NQNFS)
- authsiz += 2 * NFSX_UNSIGNED;
MGETHDR(mb, M_WAIT, MT_DATA);
- if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
+ if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
MCLGET(mb, M_WAIT);
- } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
- MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
+ } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
+ MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
} else {
- MH_ALIGN(mb, 8*NFSX_UNSIGNED);
+ MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
}
mb->m_len = 0;
mreq = mb;
@@ -205,20 +630,26 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
/*
* First the RPC header.
*/
- nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
+ nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
if (++nfs_xid == 0)
nfs_xid++;
*tl++ = *xidp = txdr_unsigned(nfs_xid);
*tl++ = rpc_call;
*tl++ = rpc_vers;
- if (nqnfs) {
+ if (nmflag & NFSMNT_NQNFS) {
*tl++ = txdr_unsigned(NQNFS_PROG);
- *tl++ = txdr_unsigned(NQNFS_VER1);
+ *tl++ = txdr_unsigned(NQNFS_VER3);
} else {
*tl++ = txdr_unsigned(NFS_PROG);
- *tl++ = txdr_unsigned(NFS_VER2);
+ if (nmflag & NFSMNT_NFSV3)
+ *tl++ = txdr_unsigned(NFS_VER3);
+ else
+ *tl++ = txdr_unsigned(NFS_VER2);
}
- *tl++ = txdr_unsigned(procid);
+ if (nmflag & NFSMNT_NFSV3)
+ *tl++ = txdr_unsigned(procid);
+ else
+ *tl++ = txdr_unsigned(nfsv2_procid[procid]);
/*
* And then the authorization cred.
@@ -237,10 +668,7 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
for (i = 1; i <= grpsiz; i++)
*tl++ = txdr_unsigned(cr->cr_groups[i]);
break;
- case RPCAUTH_NQNFS:
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(cr->cr_uid);
- *tl = txdr_unsigned(auth_len);
+ case RPCAUTH_KERB4:
siz = auth_len;
while (siz > 0) {
if (M_TRAILINGSPACE(mb) == 0) {
@@ -266,11 +694,43 @@ nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
}
break;
};
- nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(RPCAUTH_NULL);
- *tl = 0;
+
+ /*
+ * And the verifier...
+ */
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ if (verf_str) {
+ *tl++ = txdr_unsigned(RPCAUTH_KERB4);
+ *tl = txdr_unsigned(verf_len);
+ siz = verf_len;
+ while (siz > 0) {
+ if (M_TRAILINGSPACE(mb) == 0) {
+ MGET(mb2, M_WAIT, MT_DATA);
+ if (siz >= MINCLSIZE)
+ MCLGET(mb2, M_WAIT);
+ mb->m_next = mb2;
+ mb = mb2;
+ mb->m_len = 0;
+ bpos = mtod(mb, caddr_t);
+ }
+ i = min(siz, M_TRAILINGSPACE(mb));
+ bcopy(verf_str, bpos, i);
+ mb->m_len += i;
+ verf_str += i;
+ bpos += i;
+ siz -= i;
+ }
+ if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
+ for (i = 0; i < siz; i++)
+ *bpos++ = '\0';
+ mb->m_len += siz;
+ }
+ } else {
+ *tl++ = txdr_unsigned(RPCAUTH_NULL);
+ *tl = 0;
+ }
mb->m_next = mrest;
- mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
+ mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
mreq->m_pkthdr.rcvif = (struct ifnet *)0;
*mbp = mb;
return (mreq);
@@ -603,6 +1063,25 @@ nfs_init()
{
register int i;
+ /*
+ * Check to see if major data structures haven't bloated.
+ */
+ if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
+ printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
+ printf("Try reducing NFS_SMALLFH\n");
+ }
+ if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
+ printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
+ printf("Try reducing NFS_MUIDHASHSIZ\n");
+ }
+ if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
+ printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
+ printf("Try reducing NFS_UIDHASHSIZ\n");
+ }
+ if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
+ printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
+ printf("Try unionizing the nu_nickname and nu_flag fields\n");
+ }
nfsrtt.pos = 0;
rpc_vers = txdr_unsigned(RPC_VER2);
rpc_call = txdr_unsigned(RPC_CALL);
@@ -611,17 +1090,16 @@ nfs_init()
rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
rpc_autherr = txdr_unsigned(RPC_AUTHERR);
- rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
- rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
- nfs_vers = txdr_unsigned(NFS_VER2);
+ rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
nfs_prog = txdr_unsigned(NFS_PROG);
+ nqnfs_prog = txdr_unsigned(NQNFS_PROG);
nfs_true = txdr_unsigned(TRUE);
nfs_false = txdr_unsigned(FALSE);
nfs_xdrneg1 = txdr_unsigned(-1);
- /* Loop thru nfs procids */
- for (i = 0; i < NFS_NPROCS; i++)
- nfs_procids[i] = txdr_unsigned(i);
+ nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
+ if (nfs_ticks < 1)
+ nfs_ticks = 1;
/* Ensure async daemons disabled */
for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
nfs_iodwant[i] = (struct proc *)0;
@@ -637,8 +1115,6 @@ nfs_init()
nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
+ nqsrv_clockskew + nqsrv_writeslack;
NQLOADNOVRAM(nqnfsstarttime);
- nqnfs_prog = txdr_unsigned(NQNFS_PROG);
- nqnfs_vers = txdr_unsigned(NQNFS_VER1);
CIRCLEQ_INIT(&nqtimerhead);
nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
}
@@ -649,6 +1125,7 @@ nfs_init()
TAILQ_INIT(&nfs_reqq);
nfs_timer(0);
+#ifdef __FreeBSD__
/*
* Set up lease_check and lease_updatetime so that other parts
* of the system can call us, if we are loadable.
@@ -662,6 +1139,7 @@ nfs_init()
sysent[SYS_getfh].sy_narg = 2;
sysent[SYS_getfh].sy_call = getfh;
#endif
+#endif
return (0);
}
@@ -689,57 +1167,65 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
{
register struct vnode *vp = *vpp;
register struct vattr *vap;
- register struct nfsv2_fattr *fp;
+ register struct nfs_fattr *fp;
register struct nfsnode *np;
register struct nfsnodehashhead *nhpp;
register long t1;
- caddr_t dpos, cp2;
- int error = 0, isnq;
+ caddr_t cp2;
+ int error = 0, rdev;
struct mbuf *md;
enum vtype vtyp;
u_short vmode;
- long rdev;
struct timespec mtime;
struct vnode *nvp;
+ quad_t tval;
+ int v3 = NFS_ISV3(vp);
md = *mdp;
- dpos = *dposp;
- t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
- isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
- error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
- if (error)
+ t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
+ if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
return (error);
- fp = (struct nfsv2_fattr *)cp2;
- vtyp = nfstov_type(fp->fa_type);
- vmode = fxdr_unsigned(u_short, fp->fa_mode);
- /*
- * XXX
- *
- * The duplicate information returned in fa_type and fa_mode
- * is an ambiguity in the NFS version 2 protocol.
- *
- * VREG should be taken literally as a regular file. If a
- * server intents to return some type information differently
- * in the upper bits of the mode field (e.g. for sockets, or
- * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
- * leave the examination of the mode bits even in the VREG
- * case to avoid breakage for bogus servers, but we make sure
- * that there are actually type bits set in the upper part of
- * fa_mode (and failing that, trust the va_type field).
- *
- * NFSv3 cleared the issue, and requires fa_mode to not
- * contain any type information (while also introduing sockets
- * and FIFOs for fa_type).
- */
- if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
- vtyp = IFTOVT(vmode);
- if (isnq) {
- rdev = fxdr_unsigned(long, fp->fa_nqrdev);
- fxdr_nqtime(&fp->fa_nqmtime, &mtime);
+ fp = (struct nfs_fattr *)cp2;
+ if (v3) {
+ vtyp = nfsv3tov_type(fp->fa_type);
+ vmode = fxdr_unsigned(u_short, fp->fa_mode);
+ rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
+ fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
+ fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
} else {
- rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
- fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
+ vtyp = nfsv2tov_type(fp->fa_type);
+ vmode = fxdr_unsigned(u_short, fp->fa_mode);
+ /*
+ * XXX
+ *
+ * The duplicate information returned in fa_type and fa_mode
+ * is an ambiguity in the NFS version 2 protocol.
+ *
+ * VREG should be taken literally as a regular file. If a
+ * server intents to return some type information differently
+ * in the upper bits of the mode field (e.g. for sockets, or
+ * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
+ * leave the examination of the mode bits even in the VREG
+ * case to avoid breakage for bogus servers, but we make sure
+ * that there are actually type bits set in the upper part of
+ * fa_mode (and failing that, trust the va_type field).
+ *
+ * NFSv3 cleared the issue, and requires fa_mode to not
+ * contain any type information (while also introduing sockets
+ * and FIFOs for fa_type).
+ */
+ if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
+ vtyp = IFTOVT(vmode);
+ rdev = fxdr_unsigned(long, fp->fa2_rdev);
+ fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
+
+ /*
+ * Really ugly NFSv2 kludge.
+ */
+ if (vtyp == VCHR && rdev == 0xffffffff)
+ vtyp = VFIFO;
}
+
/*
* If v_type == VNON it is a new node, so fill in the v_type,
* n_mtime fields. Check to see if it represents a special
@@ -749,10 +1235,15 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
*/
np = VTONFS(vp);
if (vp->v_type == VNON) {
- if (vtyp == VCHR && rdev == 0xffffffff)
- vp->v_type = vtyp = VFIFO;
- else
- vp->v_type = vtyp;
+ /*
+ * If we had a lock and it turns out that the vnode
+ * is an object which we don't want to lock (e.g. VDIR)
+ * to avoid nasty hanging problems on a server crash,
+ * then release it here.
+ */
+ if (vtyp != VREG && VOP_ISLOCKED(vp))
+ VOP_UNLOCK(vp);
+ vp->v_type = vtyp;
if (vp->v_type == VFIFO) {
vp->v_op = fifo_nfsv2nodeop_p;
}
@@ -773,7 +1264,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
* Reinitialize aliased node.
*/
np->n_vnode = nvp;
- nhpp = nfs_hash(&np->n_fh);
+ nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize));
LIST_INSERT_HEAD(nhpp, np, n_hash);
*vpp = vp = nvp;
}
@@ -783,31 +1274,34 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
vap = &np->n_vattr;
vap->va_type = vtyp;
vap->va_mode = (vmode & 07777);
- vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
- vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
- vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
vap->va_rdev = (dev_t)rdev;
vap->va_mtime = mtime;
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
- if (isnq) {
- fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
- vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
- fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
- vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
- fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
- vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
- fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
- vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
- fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
+ if (v3) {
+ vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
+ vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
+ vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
+ fxdr_hyper(&fp->fa3_size, &vap->va_size);
+ vap->va_blocksize = NFS_FABLKSIZE;
+ fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
+ vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
+ fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
+ fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
+ vap->va_flags = 0;
+ vap->va_filerev = 0;
} else {
- vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
- vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
- vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
- vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
- fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
+ vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
+ vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
+ vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
+ vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
+ vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
+ vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
+ vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
+ fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
vap->va_flags = 0;
- fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
- vap->va_gen = 0;
+ vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
+ vap->va_ctime.ts_nsec = 0;
+ vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
vap->va_filerev = 0;
}
if (vap->va_size != np->n_size) {
@@ -824,26 +1318,13 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper)
np->n_size = vap->va_size;
}
np->n_attrstamp = time.tv_sec;
- *dposp = dpos;
- *mdp = md;
if (vaper != NULL) {
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
-#ifdef notdef
- if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
- if (np->n_size > vap->va_size)
- vaper->va_size = np->n_size;
-#endif
if (np->n_flag & NCHG) {
- if (np->n_flag & NACC) {
- vaper->va_atime.ts_sec = np->n_atim.tv_sec;
- vaper->va_atime.ts_nsec =
- np->n_atim.tv_usec * 1000;
- }
- if (np->n_flag & NUPD) {
- vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
- vaper->va_mtime.ts_nsec =
- np->n_mtim.tv_usec * 1000;
- }
+ if (np->n_flag & NACC)
+ vaper->va_atime = np->n_atim;
+ if (np->n_flag & NUPD)
+ vaper->va_mtime = np->n_mtim;
}
}
return (0);
@@ -862,12 +1343,7 @@ nfs_getattrcache(vp, vaper)
register struct nfsnode *np = VTONFS(vp);
register struct vattr *vap;
- if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
- if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
- nfsstats.attrcache_misses++;
- return (ENOENT);
- }
- } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
+ if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
nfsstats.attrcache_misses++;
return (ENOENT);
}
@@ -887,23 +1363,11 @@ nfs_getattrcache(vp, vaper)
np->n_size = vap->va_size;
}
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
-#ifdef notdef
- if ((np->n_flag & NMODIFIED) == 0) {
- np->n_size = vaper->va_size;
- vnode_pager_setsize(vp, (u_long)np->n_size);
- } else if (np->n_size > vaper->va_size)
- if (np->n_size > vaper->va_size)
- vaper->va_size = np->n_size;
-#endif
if (np->n_flag & NCHG) {
- if (np->n_flag & NACC) {
- vaper->va_atime.ts_sec = np->n_atim.tv_sec;
- vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
- }
- if (np->n_flag & NUPD) {
- vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
- vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
- }
+ if (np->n_flag & NACC)
+ vaper->va_atime = np->n_atim;
+ if (np->n_flag & NUPD)
+ vaper->va_mtime = np->n_mtim;
}
return (0);
}
@@ -912,7 +1376,7 @@ nfs_getattrcache(vp, vaper)
* Set up nameidata for a lookup() call and do it
*/
int
-nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
+nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
register struct nameidata *ndp;
fhandle_t *fhp;
int len;
@@ -920,7 +1384,9 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
struct mbuf *nam;
struct mbuf **mdp;
caddr_t *dposp;
+ struct vnode **retdirp;
struct proc *p;
+ int kerbflag;
{
register int i, rem;
register struct mbuf *md;
@@ -929,6 +1395,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
int error, rdonly;
struct componentname *cnp = &ndp->ni_cnd;
+ *retdirp = (struct vnode *)0;
MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
/*
* Copy the name from the mbuf list to ndp->ni_pnbuf
@@ -950,7 +1417,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
rem = md->m_len;
}
if (*fromcp == '\0' || *fromcp == '/') {
- error = EINVAL;
+ error = EACCES;
goto out;
}
cnp->cn_hash += (unsigned char)*fromcp;
@@ -964,26 +1431,24 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
if (len > 0) {
if (rem >= len)
*dposp += len;
- else {
- error = nfs_adv(mdp, dposp, len, rem);
- if (error)
- goto out;
- }
+ else if (error = nfs_adv(mdp, dposp, len, rem))
+ goto out;
}
ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
cnp->cn_nameptr = cnp->cn_pnbuf;
/*
* Extract and set starting directory.
*/
- error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
- nam, &rdonly);
- if (error)
+ if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
+ nam, &rdonly, kerbflag))
goto out;
if (dp->v_type != VDIR) {
nfsrv_vrele(dp);
error = ENOTDIR;
goto out;
}
+ VREF(dp);
+ *retdirp = dp;
ndp->ni_startdir = dp;
if (rdonly)
cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
@@ -993,8 +1458,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
* And call lookup() to do the real work
*/
cnp->cn_proc = p;
- error = lookup(ndp);
- if (error)
+ if (error = lookup(ndp))
goto out;
/*
* Check for encountering a symbolic link
@@ -1087,6 +1551,109 @@ nfsm_adj(mp, len, nul)
}
/*
+ * Make these functions instead of macros, so that the kernel text size
+ * doesn't get too big...
+ */
+void
+nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
+ struct nfsrv_descript *nfsd;
+ int before_ret;
+ register struct vattr *before_vap;
+ int after_ret;
+ struct vattr *after_vap;
+ struct mbuf **mbp;
+ char **bposp;
+{
+ register struct mbuf *mb = *mbp, *mb2;
+ register char *bpos = *bposp;
+ register u_long *tl;
+
+ if (before_ret) {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ } else {
+ nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ txdr_hyper(&(before_vap->va_size), tl);
+ tl += 2;
+ txdr_nfsv3time(&(before_vap->va_mtime), tl);
+ tl += 2;
+ txdr_nfsv3time(&(before_vap->va_ctime), tl);
+ }
+ *bposp = bpos;
+ *mbp = mb;
+ nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
+}
+
+void
+nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
+ struct nfsrv_descript *nfsd;
+ int after_ret;
+ struct vattr *after_vap;
+ struct mbuf **mbp;
+ char **bposp;
+{
+ register struct mbuf *mb = *mbp, *mb2;
+ register char *bpos = *bposp;
+ register u_long *tl;
+ register struct nfs_fattr *fp;
+
+ if (after_ret) {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
+ *tl++ = nfs_true;
+ fp = (struct nfs_fattr *)tl;
+ nfsm_srvfattr(nfsd, after_vap, fp);
+ }
+ *mbp = mb;
+ *bposp = bpos;
+}
+
+void
+nfsm_srvfattr(nfsd, vap, fp)
+ register struct nfsrv_descript *nfsd;
+ register struct vattr *vap;
+ register struct nfs_fattr *fp;
+{
+
+ fp->fa_nlink = txdr_unsigned(vap->va_nlink);
+ fp->fa_uid = txdr_unsigned(vap->va_uid);
+ fp->fa_gid = txdr_unsigned(vap->va_gid);
+ if (nfsd->nd_flag & ND_NFSV3) {
+ fp->fa_type = vtonfsv3_type(vap->va_type);
+ fp->fa_mode = vtonfsv3_mode(vap->va_mode);
+ txdr_hyper(&vap->va_size, &fp->fa3_size);
+ txdr_hyper(&vap->va_bytes, &fp->fa3_used);
+ fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
+ fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
+ fp->fa3_fsid.nfsuquad[0] = 0;
+ fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
+ fp->fa3_fileid.nfsuquad[0] = 0;
+ fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
+ txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
+ txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
+ txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
+ } else {
+ fp->fa_type = vtonfsv2_type(vap->va_type);
+ fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
+ fp->fa2_size = txdr_unsigned(vap->va_size);
+ fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
+ if (vap->va_type == VFIFO)
+ fp->fa2_rdev = 0xffffffff;
+ else
+ fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
+ fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
+ fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
+ fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
+ txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
+ txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
+ txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
+ }
+}
+
+/*
* nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
* - look up fsid in mount list (if not found ret error)
* - get vp and export rights by calling VFS_FHTOVP()
@@ -1094,7 +1661,7 @@ nfsm_adj(mp, len, nul)
* - if not lockflag unlock it with VOP_UNLOCK()
*/
int
-nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
+nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
fhandle_t *fhp;
int lockflag;
struct vnode **vpp;
@@ -1102,6 +1669,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
struct nfssvc_sock *slp;
struct mbuf *nam;
int *rdonlyp;
+ int kerbflag;
{
register struct mount *mp;
register struct nfsuid *uidp;
@@ -1120,19 +1688,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
* Check/setup credentials.
*/
if (exflags & MNT_EXKERB) {
- for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
- uidp = uidp->nu_hash.le_next) {
- if (uidp->nu_uid == cred->cr_uid)
- break;
- }
- if (uidp == 0) {
+ if (!kerbflag) {
vput(*vpp);
- return (NQNFS_AUTHERR);
+ return (NFSERR_AUTHERR | AUTH_TOOWEAK);
}
- cred->cr_uid = uidp->nu_cr.cr_uid;
- for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
- cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
- cred->cr_ngroups = i;
+ } else if (kerbflag) {
+ vput(*vpp);
+ return (NFSERR_AUTHERR | AUTH_TOOWEAK);
} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
cred->cr_uid = credanon->cr_uid;
for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
@@ -1194,6 +1756,145 @@ netaddr_match(family, haddr, nam)
return (0);
}
+static nfsuint64 nfs_nullcookie = { 0, 0 };
+/*
+ * This function finds the directory cookie that corresponds to the
+ * logical byte offset given.
+ */
+nfsuint64 *
+nfs_getcookie(np, off, add)
+ register struct nfsnode *np;
+ off_t off;
+ int add;
+{
+ register struct nfsdmap *dp, *dp2;
+ register int pos;
+
+ pos = off / NFS_DIRBLKSIZ;
+ if (pos == 0) {
+#ifdef DIAGNOSTIC
+ if (add)
+ panic("nfs getcookie add at 0");
+#endif
+ return (&nfs_nullcookie);
+ }
+ pos--;
+ dp = np->n_cookies.lh_first;
+ if (!dp) {
+ if (add) {
+ MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
+ M_NFSDIROFF, M_WAITOK);
+ dp->ndm_eocookie = 0;
+ LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
+ } else
+ return ((nfsuint64 *)0);
+ }
+ while (pos >= NFSNUMCOOKIES) {
+ pos -= NFSNUMCOOKIES;
+ if (dp->ndm_list.le_next) {
+ if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
+ pos >= dp->ndm_eocookie)
+ return ((nfsuint64 *)0);
+ dp = dp->ndm_list.le_next;
+ } else if (add) {
+ MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
+ M_NFSDIROFF, M_WAITOK);
+ dp2->ndm_eocookie = 0;
+ LIST_INSERT_AFTER(dp, dp2, ndm_list);
+ dp = dp2;
+ } else
+ return ((nfsuint64 *)0);
+ }
+ if (pos >= dp->ndm_eocookie) {
+ if (add)
+ dp->ndm_eocookie = pos + 1;
+ else
+ return ((nfsuint64 *)0);
+ }
+ return (&dp->ndm_cookies[pos]);
+}
+
+/*
+ * Invalidate cached directory information, except for the actual directory
+ * blocks (which are invalidated separately).
+ * Done mainly to avoid the use of stale offset cookies.
+ */
+void
+nfs_invaldir(vp)
+ register struct vnode *vp;
+{
+ register struct nfsnode *np = VTONFS(vp);
+
+#ifdef DIAGNOSTIC
+ if (vp->v_type != VDIR)
+ panic("nfs: invaldir not dir");
+#endif
+ np->n_direofoffset = 0;
+ np->n_cookieverf.nfsuquad[0] = 0;
+ np->n_cookieverf.nfsuquad[1] = 0;
+ if (np->n_cookies.lh_first)
+ np->n_cookies.lh_first->ndm_eocookie = 0;
+}
+
+/*
+ * The write verifier has changed (probably due to a server reboot), so all
+ * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
+ * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
+ * flag. Once done the new write verifier can be set for the mount point.
+ */
+void
+nfs_clearcommit(mp)
+ struct mount *mp;
+{
+ register struct vnode *vp, *nvp;
+ register struct buf *bp, *nbp;
+ int s;
+
+ s = splbio();
+loop:
+ for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
+ if (vp->v_mount != mp) /* Paranoia */
+ goto loop;
+ nvp = vp->v_mntvnodes.le_next;
+ for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
+ nbp = bp->b_vnbufs.le_next;
+ if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
+ == (B_DELWRI | B_NEEDCOMMIT))
+ bp->b_flags &= ~B_NEEDCOMMIT;
+ }
+ }
+ splx(s);
+}
+
+/*
+ * Map errnos to NFS error numbers. For Version 3 also filter out error
+ * numbers not specified for the associated procedure.
+ */
+int
+nfsrv_errmap(nd, err)
+ struct nfsrv_descript *nd;
+ register int err;
+{
+ register short *defaulterrp, *errp;
+
+ if (nd->nd_flag & ND_NFSV3) {
+ if (nd->nd_procnum <= NFSPROC_COMMIT) {
+ errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
+ while (*++errp) {
+ if (*errp == err)
+ return (err);
+ else if (*errp > err)
+ break;
+ }
+ return ((int)*defaulterrp);
+ } else
+ return (err & 0xffff);
+ }
+ if (err <= ELAST)
+ return ((int)nfsrv_v2errmap[err - 1]);
+ return (NFSERR_IO);
+}
+
int
nfsrv_vmio( struct vnode *vp) {
vm_object_t object;
diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c
index f7e159fd6235..35a50f400c39 100644
--- a/sys/nfs/nfs_syscalls.c
+++ b/sys/nfs/nfs_syscalls.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94
- * $Id: nfs_syscalls.c,v 1.5 1994/10/17 17:47:38 phk Exp $
+ * $Id: nfs_syscalls.c,v 1.6 1995/05/30 08:12:45 rgrimes Exp $
*/
#include <sys/param.h>
@@ -61,9 +61,11 @@
#ifdef ISO
#include <netiso/iso.h>
#endif
+#include <nfs/xdr_subs.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
+#include <nfs/nfsm_subs.h>
#include <nfs/nfsrvcache.h>
#include <nfs/nfsmount.h>
#include <nfs/nfsnode.h>
@@ -73,13 +75,14 @@
void nfsrv_zapsock __P((struct nfssvc_sock *));
/* Global defs. */
-extern u_long nfs_prog, nfs_vers;
-extern int (*nfsrv_procs[NFS_NPROCS])();
+extern int (*nfsrv3_procs[NFS_NPROCS])();
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern int nfs_numasync;
extern time_t nqnfsstarttime;
extern int nqsrv_writeslack;
extern int nfsrtton;
+extern struct nfsstats nfsstats;
+extern int nfsrvw_procrastinate;
struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
int nuidhash_max = NFS_MAXUIDHASH;
static int nfs_numnfsd = 0;
@@ -225,19 +228,25 @@ nfssvc(p, uap, retval)
if (error)
return (error);
if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
- (nfsd->nd_slp->ns_flag & SLP_VALID)) {
- slp = nfsd->nd_slp;
+ (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
+ slp = nfsd->nfsd_slp;
/*
* First check to see if another nfsd has already
* added this credential.
*/
- for (nuidp = NUIDHASH(slp, nsd->nsd_uid)->lh_first;
+ for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
- if (nuidp->nu_uid == nsd->nsd_uid)
+ if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
+ (!nfsd->nfsd_nd->nd_nam2 ||
+ netaddr_match(NU_NETFAM(nuidp),
+ &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
break;
}
- if (!nuidp) {
+ if (nuidp) {
+ nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
+ nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
+ } else {
/*
* Nope, so we will.
*/
@@ -257,22 +266,53 @@ nfssvc(p, uap, retval)
LIST_REMOVE(nuidp, nu_hash);
TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
nu_lru);
+ if (nuidp->nu_flag & NU_NAM)
+ m_freem(nuidp->nu_nam);
}
+ nuidp->nu_flag = 0;
nuidp->nu_cr = nsd->nsd_cr;
if (nuidp->nu_cr.cr_ngroups > NGROUPS)
- nuidp->nu_cr.cr_ngroups = NGROUPS;
+ nuidp->nu_cr.cr_ngroups = NGROUPS;
nuidp->nu_cr.cr_ref = 1;
- nuidp->nu_uid = nsd->nsd_uid;
+ nuidp->nu_timestamp = nsd->nsd_timestamp;
+ nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl;
+ /*
+ * and save the session key in nu_key.
+ */
+ bcopy(nsd->nsd_key, nuidp->nu_key,
+ sizeof (nsd->nsd_key));
+ if (nfsd->nfsd_nd->nd_nam2) {
+ struct sockaddr_in *saddr;
+
+ saddr = mtod(nfsd->nfsd_nd->nd_nam2,
+ struct sockaddr_in *);
+ switch (saddr->sin_family) {
+ case AF_INET:
+ nuidp->nu_flag |= NU_INETADDR;
+ nuidp->nu_inetaddr =
+ saddr->sin_addr.s_addr;
+ break;
+ case AF_ISO:
+ default:
+ nuidp->nu_flag |= NU_NAM;
+ nuidp->nu_nam = m_copym(
+ nfsd->nfsd_nd->nd_nam2, 0,
+ M_COPYALL, M_WAIT);
+ break;
+ };
+ }
TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
nu_lru);
LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
nuidp, nu_hash);
-
+ nfsrv_setcred(&nuidp->nu_cr,
+ &nfsd->nfsd_nd->nd_cr);
+ nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
}
}
}
if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
- nfsd->nd_flag |= NFSD_AUTHFAIL;
+ nfsd->nfsd_flag |= NFSD_AUTHFAIL;
error = nfssvc_nfsd(nsd, uap->argp, p);
}
if (error == EINTR || error == ERESTART)
@@ -353,8 +393,6 @@ nfssvc_addsock(fp, mynam)
slp = (struct nfssvc_sock *)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
- slp->ns_uidhashtbl =
- hashinit(NUIDHASHSIZ, M_NFSSVC, &slp->ns_uidhash);
TAILQ_INIT(&slp->ns_uidlruhead);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
}
@@ -381,44 +419,47 @@ nfssvc_nfsd(nsd, argp, p)
caddr_t argp;
struct proc *p;
{
- register struct mbuf *m, *nam2;
+ register struct mbuf *m;
register int siz;
register struct nfssvc_sock *slp;
register struct socket *so;
register int *solockp;
- struct nfsd *nd = nsd->nsd_nfsd;
- struct mbuf *mreq, *nam;
- struct timeval starttime;
+ struct nfsd *nfsd = nsd->nsd_nfsd;
+ struct nfsrv_descript *nd = NULL;
+ struct mbuf *mreq;
struct nfsuid *uidp;
- int error = 0, cacherep, s;
- int sotype;
+ int error = 0, cacherep, s, sotype, writes_todo;
+ u_quad_t cur_usec;
+#ifndef nolint
+ cacherep = RC_DOIT;
+ writes_todo = 0;
+#endif
s = splnet();
- if (nd == (struct nfsd *)0) {
- nsd->nsd_nfsd = nd = (struct nfsd *)
+ if (nfsd == (struct nfsd *)0) {
+ nsd->nsd_nfsd = nfsd = (struct nfsd *)
malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
- bzero((caddr_t)nd, sizeof (struct nfsd));
- nd->nd_procp = p;
- nd->nd_cr.cr_ref = 1;
- TAILQ_INSERT_TAIL(&nfsd_head, nd, nd_chain);
- nd->nd_nqlflag = NQL_NOVAL;
+ bzero((caddr_t)nfsd, sizeof (struct nfsd));
+ nfsd->nfsd_procp = p;
+ TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
nfs_numnfsd++;
}
/*
* Loop getting rpc requests until SIGKILL.
*/
for (;;) {
- if ((nd->nd_flag & NFSD_REQINPROG) == 0) {
- while (nd->nd_slp == (struct nfssvc_sock *)0 &&
+ if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
+ while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
(nfsd_head_flag & NFSD_CHECKSLP) == 0) {
- nd->nd_flag |= NFSD_WAITING;
+ nfsd->nfsd_flag |= NFSD_WAITING;
nfsd_waiting++;
- error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0);
+ error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
+ "nfsd", 0);
nfsd_waiting--;
if (error)
goto done;
}
- if (nd->nd_slp == (struct nfssvc_sock *)0 &&
+ if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
(nfsd_head_flag & NFSD_CHECKSLP) != 0) {
for (slp = nfssvc_sockhead.tqh_first; slp != 0;
slp = slp->ns_chain.tqe_next) {
@@ -426,14 +467,14 @@ nfssvc_nfsd(nsd, argp, p)
== (SLP_VALID | SLP_DOREC)) {
slp->ns_flag &= ~SLP_DOREC;
slp->ns_sref++;
- nd->nd_slp = slp;
+ nfsd->nfsd_slp = slp;
break;
}
}
if (slp == 0)
nfsd_head_flag &= ~NFSD_CHECKSLP;
}
- if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0)
+ if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
continue;
if (slp->ns_flag & SLP_VALID) {
if (slp->ns_flag & SLP_DISCONN)
@@ -446,86 +487,78 @@ nfssvc_nfsd(nsd, argp, p)
M_WAIT);
nfs_sndunlock(&slp->ns_solock);
}
- error = nfsrv_dorec(slp, nd);
- nd->nd_flag |= NFSD_REQINPROG;
+ error = nfsrv_dorec(slp, nfsd, &nd);
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 +
+ (u_quad_t)time.tv_usec;
+ if (error && slp->ns_tq.lh_first &&
+ slp->ns_tq.lh_first->nd_time <= cur_usec) {
+ error = 0;
+ cacherep = RC_DOIT;
+ writes_todo = 1;
+ } else
+ writes_todo = 0;
+ nfsd->nfsd_flag |= NFSD_REQINPROG;
}
} else {
error = 0;
- slp = nd->nd_slp;
+ slp = nfsd->nfsd_slp;
}
if (error || (slp->ns_flag & SLP_VALID) == 0) {
- nd->nd_slp = (struct nfssvc_sock *)0;
- nd->nd_flag &= ~NFSD_REQINPROG;
+ if (nd) {
+ free((caddr_t)nd, M_NFSRVDESC);
+ nd = NULL;
+ }
+ nfsd->nfsd_slp = (struct nfssvc_sock *)0;
+ nfsd->nfsd_flag &= ~NFSD_REQINPROG;
nfsrv_slpderef(slp);
continue;
}
splx(s);
so = slp->ns_so;
sotype = so->so_type;
- starttime = time;
if (so->so_proto->pr_flags & PR_CONNREQUIRED)
solockp = &slp->ns_solock;
else
solockp = (int *)0;
- /*
- * nam == nam2 for connectionless protocols such as UDP
- * nam2 == NULL for connection based protocols to disable
- * recent request caching.
- */
- nam2 = nd->nd_nam;
- if (nam2) {
- nam = nam2;
- cacherep = RC_CHECKIT;
- } else {
- nam = slp->ns_nam;
- cacherep = RC_DOIT;
- }
-
- /*
- * Check to see if authorization is needed.
- */
- if (nd->nd_flag & NFSD_NEEDAUTH) {
- static int logauth = 0;
+ if (nd) {
+ nd->nd_starttime = time;
+ if (nd->nd_nam2)
+ nd->nd_nam = nd->nd_nam2;
+ else
+ nd->nd_nam = slp->ns_nam;
- nd->nd_flag &= ~NFSD_NEEDAUTH;
- /*
- * Check for a mapping already installed.
- */
- for (uidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first;
- uidp != 0; uidp = uidp->nu_hash.le_next) {
- if (uidp->nu_uid == nd->nd_cr.cr_uid)
- break;
- }
- if (!uidp) {
- nsd->nsd_uid = nd->nd_cr.cr_uid;
- if (nam2 && logauth++ == 0)
- log(LOG_WARNING, "Kerberized NFS using UDP\n");
- nsd->nsd_haddr =
- mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
- nsd->nsd_authlen = nd->nd_authlen;
- if (copyout(nd->nd_authstr, nsd->nsd_authstr,
- nd->nd_authlen) == 0 &&
- copyout((caddr_t)nsd, argp, sizeof (*nsd)) == 0)
- return (ENEEDAUTH);
- cacherep = RC_DROPIT;
- }
- }
- if (cacherep == RC_CHECKIT)
- cacherep = nfsrv_getcache(nam2, nd, &mreq);
+ /*
+ * Check to see if authorization is needed.
+ */
+ if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
+ nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
+ nsd->nsd_haddr = mtod(nd->nd_nam,
+ struct sockaddr_in *)->sin_addr.s_addr;
+ nsd->nsd_authlen = nfsd->nfsd_authlen;
+ nsd->nsd_verflen = nfsd->nfsd_verflen;
+ if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
+ nfsd->nfsd_authlen) &&
+ !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
+ nfsd->nfsd_verflen) &&
+ !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
+ return (ENEEDAUTH);
+ cacherep = RC_DROPIT;
+ } else
+ cacherep = nfsrv_getcache(nd, slp, &mreq);
- /*
- * Check for just starting up for NQNFS and send
- * fake "try again later" replies to the NQNFS clients.
- */
- if (notstarted && nqnfsstarttime <= time.tv_sec) {
+ /*
+ * Check for just starting up for NQNFS and send
+ * fake "try again later" replies to the NQNFS clients.
+ */
+ if (notstarted && nqnfsstarttime <= time.tv_sec) {
if (modify_flag) {
nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
modify_flag = 0;
} else
notstarted = 0;
- }
- if (notstarted) {
- if (nd->nd_nqlflag == NQL_NOVAL)
+ }
+ if (notstarted) {
+ if ((nd->nd_flag & ND_NQNFS) == 0)
cacherep = RC_DROPIT;
else if (nd->nd_procnum != NFSPROC_WRITE) {
nd->nd_procnum = NFSPROC_NOOP;
@@ -533,36 +566,42 @@ nfssvc_nfsd(nsd, argp, p)
cacherep = RC_DOIT;
} else
modify_flag = 1;
- } else if (nd->nd_flag & NFSD_AUTHFAIL) {
- nd->nd_flag &= ~NFSD_AUTHFAIL;
+ } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
+ nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
nd->nd_procnum = NFSPROC_NOOP;
- nd->nd_repstat = NQNFS_AUTHERR;
+ nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
cacherep = RC_DOIT;
+ }
}
- switch (cacherep) {
- case RC_DOIT:
- error = (*(nfsrv_procs[nd->nd_procnum]))(nd,
- nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr,
- nam, &mreq);
- if (nd->nd_cr.cr_ref != 1) {
- printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref);
- panic("nfssvc cref");
- }
+ /*
+ * Loop to get all the write rpc relies that have been
+ * gathered together.
+ */
+ do {
+ switch (cacherep) {
+ case RC_DOIT:
+ if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
+ nfsrvw_procrastinate > 0 && !notstarted))
+ error = nfsrv_writegather(&nd, slp,
+ nfsd->nfsd_procp, &mreq);
+ else
+ error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
+ slp, nfsd->nfsd_procp, &mreq);
+ if (mreq == NULL)
+ break;
if (error) {
if (nd->nd_procnum != NQNFSPROC_VACATED)
nfsstats.srv_errs++;
- if (nam2) {
- nfsrv_updatecache(nam2, nd, FALSE, mreq);
- m_freem(nam2);
- }
+ nfsrv_updatecache(nd, FALSE, mreq);
+ if (nd->nd_nam2)
+ m_freem(nd->nd_nam2);
break;
}
nfsstats.srvrpccnt[nd->nd_procnum]++;
- if (nam2)
- nfsrv_updatecache(nam2, nd, TRUE, mreq);
+ nfsrv_updatecache(nd, TRUE, mreq);
nd->nd_mrep = (struct mbuf *)0;
- case RC_REPLY:
+ case RC_REPLY:
m = mreq;
siz = 0;
while (m) {
@@ -587,15 +626,15 @@ nfssvc_nfsd(nsd, argp, p)
if (solockp)
(void) nfs_sndlock(solockp, (struct nfsreq *)0);
if (slp->ns_flag & SLP_VALID)
- error = nfs_send(so, nam2, m, (struct nfsreq *)0);
+ error = nfs_send(so, nd->nd_nam2, m, NULL);
else {
error = EPIPE;
m_freem(m);
}
if (nfsrtton)
- nfsd_rt(&starttime, sotype, nd, nam, cacherep);
- if (nam2)
- MFREE(nam2, m);
+ nfsd_rt(sotype, nd, cacherep);
+ if (nd->nd_nam2)
+ MFREE(nd->nd_nam2, m);
if (nd->nd_mrep)
m_freem(nd->nd_mrep);
if (error == EPIPE)
@@ -603,29 +642,50 @@ nfssvc_nfsd(nsd, argp, p)
if (solockp)
nfs_sndunlock(solockp);
if (error == EINTR || error == ERESTART) {
+ free((caddr_t)nd, M_NFSRVDESC);
nfsrv_slpderef(slp);
s = splnet();
goto done;
}
break;
- case RC_DROPIT:
+ case RC_DROPIT:
if (nfsrtton)
- nfsd_rt(&starttime, sotype, nd, nam, cacherep);
+ nfsd_rt(sotype, nd, cacherep);
m_freem(nd->nd_mrep);
- m_freem(nam2);
+ m_freem(nd->nd_nam2);
break;
- };
+ };
+ if (nd) {
+ FREE((caddr_t)nd, M_NFSRVDESC);
+ nd = NULL;
+ }
+
+ /*
+ * Check to see if there are outstanding writes that
+ * need to be serviced.
+ */
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 +
+ (u_quad_t)time.tv_usec;
+ s = splsoftclock();
+ if (slp->ns_tq.lh_first &&
+ slp->ns_tq.lh_first->nd_time <= cur_usec) {
+ cacherep = RC_DOIT;
+ writes_todo = 1;
+ } else
+ writes_todo = 0;
+ splx(s);
+ } while (writes_todo);
s = splnet();
- if (nfsrv_dorec(slp, nd)) {
- nd->nd_flag &= ~NFSD_REQINPROG;
- nd->nd_slp = (struct nfssvc_sock *)0;
+ if (nfsrv_dorec(slp, nfsd, &nd)) {
+ nfsd->nfsd_flag &= ~NFSD_REQINPROG;
+ nfsd->nfsd_slp = NULL;
nfsrv_slpderef(slp);
}
}
done:
- TAILQ_REMOVE(&nfsd_head, nd, nd_chain);
+ TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
splx(s);
- free((caddr_t)nd, M_NFSD);
+ free((caddr_t)nfsd, M_NFSD);
nsd->nsd_nfsd = (struct nfsd *)0;
if (--nfs_numnfsd == 0)
nfsrv_init(TRUE); /* Reinitialize everything */
@@ -641,9 +701,10 @@ int
nfssvc_iod(p)
struct proc *p;
{
- register struct buf *bp;
+ register struct buf *bp, *nbp;
register int i, myiod;
- int error = 0;
+ struct vnode *vp;
+ int error = 0, s;
/*
* Assign my position or return error if too many already running
@@ -662,24 +723,53 @@ nfssvc_iod(p)
* Just loop around doin our stuff until SIGKILL
*/
for (;;) {
- while (nfs_bufq.tqh_first == NULL && error == 0) {
- nfs_iodwant[myiod] = p;
- error = tsleep((caddr_t)&nfs_iodwant[myiod],
- PWAIT | PCATCH, "nfsidl", 0);
- }
- while ((bp = nfs_bufq.tqh_first) != NULL) {
- /* Take one off the front of the list */
- TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
- if (bp->b_flags & B_READ)
- (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
- else
- (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
- }
- if (error) {
- nfs_asyncdaemon[myiod] = 0;
- nfs_numasync--;
- return (error);
- }
+ while (nfs_bufq.tqh_first == NULL && error == 0) {
+ nfs_iodwant[myiod] = p;
+ error = tsleep((caddr_t)&nfs_iodwant[myiod],
+ PWAIT | PCATCH, "nfsidl", 0);
+ }
+ while ((bp = nfs_bufq.tqh_first) != NULL) {
+ /* Take one off the front of the list */
+ TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
+ if (bp->b_flags & B_READ)
+ (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
+ else do {
+ /*
+ * Look for a delayed write for the same vnode, so I can do
+ * it now. We must grab it before calling nfs_doio() to
+ * avoid any risk of the vnode getting vclean()'d while
+ * we are doing the write rpc.
+ */
+ vp = bp->b_vp;
+ s = splbio();
+ for (nbp = vp->v_dirtyblkhd.lh_first; nbp;
+ nbp = nbp->b_vnbufs.le_next) {
+ if ((nbp->b_flags &
+ (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI)
+ continue;
+ bremfree(nbp);
+ vfs_busy_pages(nbp, 1);
+ nbp->b_flags |= (B_BUSY|B_ASYNC);
+ break;
+ }
+ splx(s);
+ /*
+ * For the delayed write, do the first part of nfs_bwrite()
+ * up to, but not including nfs_strategy().
+ */
+ if (nbp) {
+ nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
+ reassignbuf(nbp, nbp->b_vp);
+ nbp->b_vp->v_numoutput++;
+ }
+ (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
+ } while (bp = nbp);
+ }
+ if (error) {
+ nfs_asyncdaemon[myiod] = 0;
+ nfs_numasync--;
+ return (error);
+ }
}
}
@@ -695,9 +785,11 @@ nfsrv_zapsock(slp)
register struct nfssvc_sock *slp;
{
register struct nfsuid *nuidp, *nnuidp;
+ register struct nfsrv_descript *nwp, *nnwp;
struct socket *so;
struct file *fp;
struct mbuf *m;
+ int s;
slp->ns_flag &= ~SLP_ALLFLAGS;
fp = slp->ns_fp;
@@ -716,8 +808,18 @@ nfsrv_zapsock(slp)
nnuidp = nuidp->nu_lru.tqe_next;
LIST_REMOVE(nuidp, nu_hash);
TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
+ if (nuidp->nu_flag & NU_NAM)
+ m_freem(nuidp->nu_nam);
free((caddr_t)nuidp, M_NFSUID);
}
+ s = splsoftclock();
+ for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
+ nnwp = nwp->nd_tq.le_next;
+ LIST_REMOVE(nwp, nd_tq);
+ free((caddr_t)nwp, M_NFSRVDESC);
+ }
+ LIST_INIT(&slp->ns_tq);
+ splx(s);
}
}
@@ -726,13 +828,15 @@ nfsrv_zapsock(slp)
* on this mount point porpous out of the kernel and do it.
*/
int
-nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
+nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
register struct nfsmount *nmp;
struct nfsreq *rep;
struct ucred *cred;
- int *auth_type;
char **auth_str;
int *auth_len;
+ char *verf_str;
+ int *verf_len;
+ NFSKERBKEY_T key; /* return session key */
{
int error = 0;
@@ -748,6 +852,9 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
}
nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
+ nmp->nm_authlen = RPCAUTH_MAXSIZ;
+ nmp->nm_verfstr = verf_str;
+ nmp->nm_verflen = *verf_len;
nmp->nm_authuid = cred->cr_uid;
wakeup((caddr_t)&nmp->nm_authstr);
@@ -766,8 +873,9 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
if (error)
free((caddr_t)*auth_str, M_TEMP);
else {
- *auth_type = nmp->nm_authtype;
*auth_len = nmp->nm_authlen;
+ *verf_len = nmp->nm_verflen;
+ bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
}
nmp->nm_flag &= ~NFSMNT_HASAUTH;
nmp->nm_flag |= NFSMNT_WAITAUTH;
@@ -779,6 +887,149 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
}
/*
+ * Get a nickname authenticator and verifier.
+ */
+int
+nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
+ struct nfsmount *nmp;
+ struct ucred *cred;
+ char **auth_str;
+ int *auth_len;
+ char *verf_str;
+ int verf_len;
+{
+ register struct nfsuid *nuidp;
+ register u_long *nickp, *verfp;
+ struct timeval ktvin, ktvout;
+ NFSKERBKEYSCHED_T keys; /* stores key schedule */
+
+#ifdef DIAGNOSTIC
+ if (verf_len < (4 * NFSX_UNSIGNED))
+ panic("nfs_getnickauth verf too small");
+#endif
+ for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
+ nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
+ if (nuidp->nu_cr.cr_uid == cred->cr_uid)
+ break;
+ }
+ if (!nuidp || nuidp->nu_expire < time.tv_sec)
+ return (EACCES);
+
+ /*
+ * Move to the end of the lru list (end of lru == most recently used).
+ */
+ TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
+ TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
+
+ nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
+ *nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
+ *nickp = txdr_unsigned(nuidp->nu_nickname);
+ *auth_str = (char *)nickp;
+ *auth_len = 2 * NFSX_UNSIGNED;
+
+ /*
+ * Now we must encrypt the verifier and package it up.
+ */
+ verfp = (u_long *)verf_str;
+ *verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
+ if (time.tv_sec > nuidp->nu_timestamp.tv_sec ||
+ (time.tv_sec == nuidp->nu_timestamp.tv_sec &&
+ time.tv_usec > nuidp->nu_timestamp.tv_usec))
+ nuidp->nu_timestamp = time;
+ else
+ nuidp->nu_timestamp.tv_usec++;
+ ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
+ ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
+
+ /*
+ * Now encrypt the timestamp verifier in ecb mode using the session
+ * key.
+ */
+#ifdef NFSKERB
+ XXX
+#endif
+
+ *verfp++ = ktvout.tv_sec;
+ *verfp++ = ktvout.tv_usec;
+ *verfp = 0;
+ return (0);
+}
+
+/*
+ * Save the current nickname in a hash list entry on the mount point.
+ */
+int
+nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
+ register struct nfsmount *nmp;
+ struct ucred *cred;
+ int len;
+ NFSKERBKEY_T key;
+ struct mbuf **mdp;
+ char **dposp;
+ struct mbuf *mrep;
+{
+ register struct nfsuid *nuidp;
+ register u_long *tl;
+ register long t1;
+ struct mbuf *md = *mdp;
+ struct timeval ktvin, ktvout;
+ u_long nick;
+ NFSKERBKEYSCHED_T keys;
+ char *dpos = *dposp, *cp2;
+ int deltasec, error = 0;
+
+ if (len == (3 * NFSX_UNSIGNED)) {
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ ktvin.tv_sec = *tl++;
+ ktvin.tv_usec = *tl++;
+ nick = fxdr_unsigned(u_long, *tl);
+
+ /*
+ * Decrypt the timestamp in ecb mode.
+ */
+#ifdef NFSKERB
+ XXX
+#endif
+ ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
+ ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
+ deltasec = time.tv_sec - ktvout.tv_sec;
+ if (deltasec < 0)
+ deltasec = -deltasec;
+ /*
+ * If ok, add it to the hash list for the mount point.
+ */
+ if (deltasec <= NFS_KERBCLOCKSKEW) {
+ if (nmp->nm_numuids < nuidhash_max) {
+ nmp->nm_numuids++;
+ nuidp = (struct nfsuid *)
+ malloc(sizeof (struct nfsuid), M_NFSUID,
+ M_WAITOK);
+ } else {
+ nuidp = nmp->nm_uidlruhead.tqh_first;
+ LIST_REMOVE(nuidp, nu_hash);
+ TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
+ nu_lru);
+ }
+ nuidp->nu_flag = 0;
+ nuidp->nu_cr.cr_uid = cred->cr_uid;
+ nuidp->nu_expire = time.tv_sec + NFS_KERBTTL;
+ nuidp->nu_timestamp = ktvout;
+ nuidp->nu_nickname = nick;
+ bcopy(key, nuidp->nu_key, sizeof (key));
+ TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
+ nu_lru);
+ LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
+ nuidp, nu_hash);
+ }
+ } else
+ nfsm_adv(nfsm_rndup(len));
+nfsmout:
+ *mdp = md;
+ *dposp = dpos;
+ return (error);
+}
+
+/*
* Derefence a server socket structure. If it has no more references and
* is no longer valid, you can throw it away.
*/
@@ -830,16 +1081,12 @@ nfsrv_init(terminating)
nfs_udpsock = (struct nfssvc_sock *)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
- nfs_udpsock->ns_uidhashtbl =
- hashinit(NUIDHASHSIZ, M_NFSSVC, &nfs_udpsock->ns_uidhash);
TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
nfs_cltpsock = (struct nfssvc_sock *)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
- nfs_cltpsock->ns_uidhashtbl =
- hashinit(NUIDHASHSIZ, M_NFSSVC, &nfs_cltpsock->ns_uidhash);
TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
}
@@ -848,11 +1095,9 @@ nfsrv_init(terminating)
* Add entries to the server monitor log.
*/
static void
-nfsd_rt(startp, sotype, nd, nam, cacherep)
- struct timeval *startp;
+nfsd_rt(sotype, nd, cacherep)
int sotype;
- register struct nfsd *nd;
- struct mbuf *nam;
+ register struct nfsrv_descript *nd;
int cacherep;
{
register struct drt *rt;
@@ -866,15 +1111,17 @@ nfsd_rt(startp, sotype, nd, nam, cacherep)
rt->flag = DRT_CACHEDROP;
if (sotype == SOCK_STREAM)
rt->flag |= DRT_TCP;
- if (nd->nd_nqlflag != NQL_NOVAL)
+ if (nd->nd_flag & ND_NQNFS)
rt->flag |= DRT_NQNFS;
+ else if (nd->nd_flag & ND_NFSV3)
+ rt->flag |= DRT_NFSV3;
rt->proc = nd->nd_procnum;
- if (mtod(nam, struct sockaddr *)->sa_family == AF_INET)
- rt->ipadr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
+ if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
+ rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
else
- rt->ipadr = INADDR_ANY;
- rt->resptime = ((time.tv_sec - startp->tv_sec) * 1000000) +
- (time.tv_usec - startp->tv_usec);
+ rt->ipadr = INADDR_ANY;
+ rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
+ (time.tv_usec - nd->nd_starttime.tv_usec);
rt->tstamp = time;
nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
}
diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c
index 2daa89117aa1..2c4070b7e8ca 100644
--- a/sys/nfs/nfs_vfsops.c
+++ b/sys/nfs/nfs_vfsops.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94
- * $Id: nfs_vfsops.c,v 1.14.2.1 1995/06/02 11:13:15 davidg Exp $
+ * $Id: nfs_vfsops.c,v 1.15 1995/06/11 19:31:46 rgrimes Exp $
*/
#include <sys/param.h>
@@ -59,10 +59,10 @@
#include <netinet/in.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfsnode.h>
-#include <nfs/nfsmount.h>
#include <nfs/nfs.h>
+#include <nfs/nfsmount.h>
#include <nfs/xdr_subs.h>
#include <nfs/nfsm_subs.h>
#include <nfs/nfsdiskless.h>
@@ -71,11 +71,15 @@
struct nfsstats nfsstats;
static int nfs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
struct proc *);
+extern int nfs_ticks;
/*
* nfs vfs operations.
*/
struct vfsops nfs_vfsops = {
+#ifdef __NetBSD__
+ MOUNT_NFS,
+#endif
nfs_mount,
nfs_start,
nfs_unmount,
@@ -87,9 +91,13 @@ struct vfsops nfs_vfsops = {
nfs_fhtovp,
nfs_vptofh,
nfs_init,
+#ifdef __FreeBSD__
nfs_sysctl
+#endif
};
+#ifdef __FreeBSD__
VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
+#endif
/*
* This structure must be filled in by a primary bootstrap or bootstrap
@@ -99,16 +107,11 @@ VFS_SET(nfs_vfsops, nfs, MOUNT_NFS, VFCF_NETWORK);
struct nfs_diskless nfs_diskless = { 0 };
int nfs_diskless_valid = 0;
-extern u_long nfs_procids[NFS_NPROCS];
-extern u_long nfs_prog, nfs_vers;
void nfs_disconnect __P((struct nfsmount *));
void nfsargs_ntoh __P((struct nfs_args *));
static struct mount *nfs_mountdiskless __P((char *, char *, int,
struct sockaddr_in *, struct nfs_args *, register struct vnode **));
-#define TRUE 1
-#define FALSE 0
-
/*
* nfs statfs call
*/
@@ -119,40 +122,65 @@ nfs_statfs(mp, sbp, p)
struct proc *p;
{
register struct vnode *vp;
- register struct nfsv2_statfs *sfp;
+ register struct nfs_statfs *sfp;
register caddr_t cp;
- register long t1;
+ register u_long *tl;
+ register long t1, t2;
caddr_t bpos, dpos, cp2;
- int error = 0, isnq;
+ struct nfsmount *nmp = VFSTONFS(mp);
+ int error = 0, v3 = (nmp->nm_flag & NFSMNT_NFSV3), retattr;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- struct nfsmount *nmp;
struct ucred *cred;
struct nfsnode *np;
+ u_quad_t tquad;
- nmp = VFSTONFS(mp);
- isnq = (nmp->nm_flag & NFSMNT_NQNFS);
- error = nfs_nget(mp, &nmp->nm_fh, &np);
+#ifndef nolint
+ sfp = (struct nfs_statfs *)0;
+#endif
+ error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
if (error)
return (error);
vp = NFSTOV(np);
- nfsstats.rpccnt[NFSPROC_STATFS]++;
cred = crget();
cred->cr_ngroups = 1;
- nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
- nfsm_fhtom(vp);
- nfsm_request(vp, NFSPROC_STATFS, p, cred);
- nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
+ if (v3 && (nmp->nm_flag & NFSMNT_GOTFSINFO) == 0)
+ (void)nfs_fsinfo(nmp, vp, cred, p);
+ nfsstats.rpccnt[NFSPROC_FSSTAT]++;
+ nfsm_reqhead(vp, NFSPROC_FSSTAT, NFSX_FH(v3));
+ nfsm_fhtom(vp, v3);
+ nfsm_request(vp, NFSPROC_FSSTAT, p, cred);
+ if (v3)
+ nfsm_postop_attr(vp, retattr);
+ if (!error)
+ nfsm_dissect(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
+#ifdef __NetBSD__
+#ifdef COMPAT_09
+ sbp->f_type = 2;
+#else
+ sbp->f_type = 0;
+#endif
+#else
sbp->f_type = MOUNT_NFS;
+#endif
sbp->f_flags = nmp->nm_flag;
- sbp->f_iosize = NFS_MAXDGRAMDATA;
- sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
- sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
- sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
- sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
- if (isnq) {
- sbp->f_files = fxdr_unsigned(long, sfp->sf_files);
- sbp->f_ffree = fxdr_unsigned(long, sfp->sf_ffree);
+ sbp->f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
+ if (v3) {
+ sbp->f_bsize = NFS_FABLKSIZE;
+ fxdr_hyper(&sfp->sf_tbytes, &tquad);
+ sbp->f_blocks = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
+ fxdr_hyper(&sfp->sf_fbytes, &tquad);
+ sbp->f_bfree = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
+ fxdr_hyper(&sfp->sf_abytes, &tquad);
+ sbp->f_bavail = (long)(tquad / ((u_quad_t)NFS_FABLKSIZE));
+ sbp->f_files = (fxdr_unsigned(long, sfp->sf_tfiles.nfsuquad[1])
+ & 0x7fffffff);
+ sbp->f_ffree = (fxdr_unsigned(long, sfp->sf_ffiles.nfsuquad[1])
+ & 0x7fffffff);
} else {
+ sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
+ sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
+ sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
+ sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
sbp->f_files = 0;
sbp->f_ffree = 0;
}
@@ -161,12 +189,72 @@ nfs_statfs(mp, sbp, p)
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
}
nfsm_reqdone;
- vrele(vp);
+ vput(vp);
crfree(cred);
return (error);
}
/*
+ * nfs version 3 fsinfo rpc call
+ */
+int
+nfs_fsinfo(nmp, vp, cred, p)
+ register struct nfsmount *nmp;
+ register struct vnode *vp;
+ struct ucred *cred;
+ struct proc *p;
+{
+ register struct nfsv3_fsinfo *fsp;
+ register caddr_t cp;
+ register long t1, t2;
+ register u_long *tl, pref, max;
+ caddr_t bpos, dpos, cp2;
+ int error = 0, retattr;
+ struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+
+ nfsstats.rpccnt[NFSPROC_FSINFO]++;
+ nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
+ nfsm_fhtom(vp, 1);
+ nfsm_request(vp, NFSPROC_FSINFO, p, cred);
+ nfsm_postop_attr(vp, retattr);
+ if (!error) {
+ nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
+ pref = fxdr_unsigned(u_long, fsp->fs_wtpref);
+ if (pref < nmp->nm_wsize)
+ nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) &
+ ~(NFS_FABLKSIZE - 1);
+ max = fxdr_unsigned(u_long, fsp->fs_wtmax);
+ if (max < nmp->nm_wsize) {
+ nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
+ if (nmp->nm_wsize == 0)
+ nmp->nm_wsize = max;
+ }
+ pref = fxdr_unsigned(u_long, fsp->fs_rtpref);
+ if (pref < nmp->nm_rsize)
+ nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) &
+ ~(NFS_FABLKSIZE - 1);
+ max = fxdr_unsigned(u_long, fsp->fs_rtmax);
+ if (max < nmp->nm_rsize) {
+ nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
+ if (nmp->nm_rsize == 0)
+ nmp->nm_rsize = max;
+ }
+ pref = fxdr_unsigned(u_long, fsp->fs_dtpref);
+ if (pref < nmp->nm_readdirsize)
+ nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) &
+ ~(NFS_DIRBLKSIZ - 1);
+ if (max < nmp->nm_readdirsize) {
+ nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
+ if (nmp->nm_readdirsize == 0)
+ nmp->nm_readdirsize = max;
+ }
+ nmp->nm_flag |= NFSMNT_GOTFSINFO;
+ }
+ nfsm_reqdone;
+ return (error);
+}
+
+/*
* Mount a remote root fs via. nfs. This depends on the info in the
* nfs_diskless structure that has been filled in properly by some primary
* bootstrap.
@@ -268,7 +356,12 @@ nfs_mountroot()
* Create a fake mount point just for the swap vnode so that the
* swap file can be on a different server from the rootfs.
*/
- nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh;
+ nd->swap_args.fh = nd->swap_fh;
+ /*
+ * If using nfsv3_diskless, replace NFSX_V2FH with
+ * nd->swap_fhsize.
+ */
+ nd->swap_args.fhsize = NFSX_V2FH;
l = ntohl(nd->swap_saddr.sin_addr.s_addr);
sprintf(buf,"%ld.%ld.%ld.%ld:%s",
(l >> 24) & 0xff, (l >> 16) & 0xff,
@@ -293,8 +386,12 @@ nfs_mountroot()
/*
* Create the rootfs mount point.
*/
- nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
- l = ntohl(nd->root_saddr.sin_addr.s_addr);
+ nd->root_args.fh = nd->root_fh;
+ /*
+ * If using nfsv3_diskless, replace NFSX_V2FH with nd->root_fhsize.
+ */
+ nd->root_args.fhsize = NFSX_V2FH;
+ l = ntohl(nd->swap_saddr.sin_addr.s_addr);
sprintf(buf,"%ld.%ld.%ld.%ld:%s",
(l >> 24) & 0xff, (l >> 16) & 0xff,
(l >> 8) & 0xff, (l >> 0) & 0xff,nd->root_hostnam);
@@ -304,7 +401,11 @@ nfs_mountroot()
if (vfs_lock(mp))
panic("nfs_mountroot: vfs_lock");
+#if NetBSD >= 1994101
+ CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
+#else
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
+#endif
mp->mnt_flag |= MNT_ROOTFS;
mp->mnt_vnodecovered = NULLVP;
vfs_unlock(mp);
@@ -386,12 +487,12 @@ nfs_mount(mp, path, data, ndp, p)
struct vnode *vp;
char pth[MNAMELEN], hst[MNAMELEN];
u_int len;
- nfsv2fh_t nfh;
+ u_char nfh[NFSX_V3FHMAX];
error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args));
if (error)
return (error);
- error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t));
+ error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize);
if (error)
return (error);
error = copyinstr(path, pth, MNAMELEN-1, &len);
@@ -406,7 +507,7 @@ nfs_mount(mp, path, data, ndp, p)
error = sockargs(&nam, (caddr_t)args.addr, args.addrlen, MT_SONAME);
if (error)
return (error);
- args.fh = &nfh;
+ args.fh = nfh;
error = mountnfs(&args, mp, nam, pth, hst, &vp);
return (error);
}
@@ -424,7 +525,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
{
register struct nfsmount *nmp;
struct nfsnode *np;
- int error;
+ int error, maxio;
if (mp->mnt_flag & MNT_UPDATE) {
nmp = VFSTONFS(mp);
@@ -435,16 +536,12 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
M_NFSMNT, M_WAITOK);
bzero((caddr_t)nmp, sizeof (struct nfsmount));
+ TAILQ_INIT(&nmp->nm_uidlruhead);
mp->mnt_data = (qaddr_t)nmp;
}
getnewfsid(mp, MOUNT_NFS);
nmp->nm_mountp = mp;
nmp->nm_flag = argp->flags;
- if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
- (NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
- error = EPERM;
- goto bad;
- }
if (nmp->nm_flag & NFSMNT_NQNFS)
/*
* We have to set mnt_maxsymlink to a non-zero value so
@@ -457,14 +554,24 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
nmp->nm_retry = NFS_RETRANS;
nmp->nm_wsize = NFS_WSIZE;
nmp->nm_rsize = NFS_RSIZE;
+ nmp->nm_readdirsize = NFS_READDIRSIZE;
nmp->nm_numgrps = NFS_MAXGRPS;
nmp->nm_readahead = NFS_DEFRAHEAD;
nmp->nm_leaseterm = NQ_DEFLEASE;
nmp->nm_deadthresh = NQ_DEADTHRESH;
CIRCLEQ_INIT(&nmp->nm_timerhead);
nmp->nm_inprog = NULLVP;
- bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
+ nmp->nm_fhsize = argp->fhsize;
+ bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
+#ifdef __NetBSD__
+#ifdef COMPAT_09
+ mp->mnt_stat.f_type = 2;
+#else
+ mp->mnt_stat.f_type = 0;
+#endif
+#else
mp->mnt_stat.f_type = MOUNT_NFS;
+#endif
bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
nmp->nm_nam = nam;
@@ -483,29 +590,48 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
nmp->nm_retry = NFS_MAXREXMIT;
}
+ if (argp->flags & NFSMNT_NFSV3) {
+ if (argp->sotype == SOCK_DGRAM)
+ maxio = NFS_MAXDGRAMDATA;
+ else
+ maxio = NFS_MAXDATA;
+ } else
+ maxio = NFS_V2MAXDATA;
+
if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
nmp->nm_wsize = argp->wsize;
/* Round down to multiple of blocksize */
- nmp->nm_wsize &= ~0x1ff;
+ nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1);
if (nmp->nm_wsize <= 0)
- nmp->nm_wsize = 512;
- else if (nmp->nm_wsize > NFS_MAXDATA)
- nmp->nm_wsize = NFS_MAXDATA;
+ nmp->nm_wsize = NFS_FABLKSIZE;
}
+ if (nmp->nm_wsize > maxio)
+ nmp->nm_wsize = maxio;
if (nmp->nm_wsize > MAXBSIZE)
nmp->nm_wsize = MAXBSIZE;
if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
nmp->nm_rsize = argp->rsize;
/* Round down to multiple of blocksize */
- nmp->nm_rsize &= ~0x1ff;
+ nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1);
if (nmp->nm_rsize <= 0)
- nmp->nm_rsize = 512;
- else if (nmp->nm_rsize > NFS_MAXDATA)
- nmp->nm_rsize = NFS_MAXDATA;
+ nmp->nm_rsize = NFS_FABLKSIZE;
}
+ if (nmp->nm_rsize > maxio)
+ nmp->nm_rsize = maxio;
if (nmp->nm_rsize > MAXBSIZE)
nmp->nm_rsize = MAXBSIZE;
+
+ if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) {
+ nmp->nm_readdirsize = argp->readdirsize;
+ /* Round down to multiple of blocksize */
+ nmp->nm_readdirsize &= ~(NFS_DIRBLKSIZ - 1);
+ if (nmp->nm_readdirsize < NFS_DIRBLKSIZ)
+ nmp->nm_readdirsize = NFS_DIRBLKSIZ;
+ }
+ if (nmp->nm_readdirsize > maxio)
+ nmp->nm_readdirsize = maxio;
+
if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
argp->maxgrouplist <= NFS_MAXGRPS)
nmp->nm_numgrps = argp->maxgrouplist;
@@ -536,7 +662,7 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
* stuck on a dead server and we are holding a lock on the mount
* point.
*/
- mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
+ mp->mnt_stat.f_iosize = min(nmp->nm_rsize, nmp->nm_wsize);
/*
* A reference count is needed on the nfsnode representing the
* remote root. If this object is not persistent, then backward
@@ -545,11 +671,16 @@ mountnfs(argp, mp, nam, pth, hst, vpp)
* this problem, because one can identify root inodes by their
* number == ROOTINO (2).
*/
- error = nfs_nget(mp, &nmp->nm_fh, &np);
+ error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
if (error)
goto bad;
*vpp = NFSTOV(np);
+ /*
+ * Lose the lock but keep the ref.
+ */
+ VOP_UNLOCK(*vpp);
+
return (0);
bad:
nfs_disconnect(nmp);
@@ -592,7 +723,7 @@ nfs_unmount(mp, mntflags, p)
* the remote root. See comment in mountnfs(). The VFS unmount()
* has done vput on this vnode, otherwise we would get deadlock!
*/
- error = nfs_nget(mp, &nmp->nm_fh, &np);
+ error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
if (error)
return(error);
vp = NFSTOV(np);
@@ -622,9 +753,9 @@ nfs_unmount(mp, mntflags, p)
nmp->nm_flag |= NFSMNT_DISMNT;
/*
- * There are two reference counts to get rid of here.
+ * There are two reference counts and one lock to get rid of here.
*/
- vrele(vp);
+ vput(vp);
vrele(vp);
vgone(vp);
nfs_disconnect(nmp);
@@ -649,10 +780,11 @@ nfs_root(mp, vpp)
int error;
nmp = VFSTONFS(mp);
- error = nfs_nget(mp, &nmp->nm_fh, &np);
+ error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
if (error)
return (error);
vp = NFSTOV(np);
+ VOP_UNLOCK(vp);
vp->v_type = VDIR;
vp->v_flag = VROOT;
*vpp = vp;
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index 46484eae91aa..769b0bb57813 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -34,17 +34,18 @@
* SUCH DAMAGE.
*
* @(#)nfs_vnops.c 8.5 (Berkeley) 2/13/94
- * $Id: nfs_vnops.c,v 1.14 1995/03/23 09:43:40 davidg Exp $
+ * $Id: nfs_vnops.c,v 1.15 1995/05/30 08:12:49 rgrimes Exp $
*/
/*
- * vnode op calls for sun nfs version 2
+ * vnode op calls for Sun NFS version 2 and 3
*/
#include <sys/param.h>
-#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/systm.h>
+#include <sys/resourcevar.h>
+#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/malloc.h>
@@ -53,7 +54,9 @@
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/dirent.h>
+#include <sys/fcntl.h>
#include <sys/lockf.h>
+#include <ufs/ufs/dir.h>
#include <vm/vm.h>
@@ -61,7 +64,7 @@
#include <miscfs/fifofs/fifo.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsnode.h>
#include <nfs/nfsmount.h>
@@ -69,11 +72,24 @@
#include <nfs/nfsm_subs.h>
#include <nfs/nqnfs.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
/* Defs */
#define TRUE 1
#define FALSE 0
/*
+ * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these
+ * calls are not in getblk() and brelse() so that they would not be necessary
+ * here.
+ */
+#ifndef B_VMIO
+#define vfs_busy_pages(bp, f)
+#endif
+
+/*
* Global vfs data structures for nfs
*/
int (**nfsv2_vnodeop_p)();
@@ -89,8 +105,14 @@ struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
{ &vop_setattr_desc, nfs_setattr }, /* setattr */
{ &vop_read_desc, nfs_read }, /* read */
{ &vop_write_desc, nfs_write }, /* write */
+#ifdef HAS_VOPLEASE
+ { &vop_lease_desc, nfs_lease_check }, /* lease */
+#endif
{ &vop_ioctl_desc, nfs_ioctl }, /* ioctl */
{ &vop_select_desc, nfs_select }, /* select */
+#ifdef HAS_VOPREVOKE
+ { &vop_revoke_desc, nfs_revoke }, /* revoke */
+#endif
{ &vop_mmap_desc, nfs_mmap }, /* mmap */
{ &vop_fsync_desc, nfs_fsync }, /* fsync */
{ &vop_seek_desc, nfs_seek }, /* seek */
@@ -119,12 +141,14 @@ struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
{ &vop_vfree_desc, nfs_vfree }, /* vfree */
{ &vop_truncate_desc, nfs_truncate }, /* truncate */
{ &vop_update_desc, nfs_update }, /* update */
- { &vop_bwrite_desc, vn_bwrite },
+ { &vop_bwrite_desc, nfs_bwrite },
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
};
struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
+#ifdef __FreeBSD__
VNODEOP_SET(nfsv2_vnodeop_opv_desc);
+#endif
/*
* Special device vnode ops
@@ -142,8 +166,14 @@ struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
{ &vop_setattr_desc, nfs_setattr }, /* setattr */
{ &vop_read_desc, nfsspec_read }, /* read */
{ &vop_write_desc, nfsspec_write }, /* write */
+#ifdef HAS_VOPLEASE
+ { &vop_lease_desc, spec_lease_check }, /* lease */
+#endif
{ &vop_ioctl_desc, spec_ioctl }, /* ioctl */
{ &vop_select_desc, spec_select }, /* select */
+#ifdef HAS_VOPREVOKE
+ { &vop_revoke_desc, spec_revoke }, /* revoke */
+#endif
{ &vop_mmap_desc, spec_mmap }, /* mmap */
{ &vop_fsync_desc, nfs_fsync }, /* fsync */
{ &vop_seek_desc, spec_seek }, /* seek */
@@ -177,7 +207,9 @@ struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
};
struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
+#ifdef __FreeBSD__
VNODEOP_SET(spec_nfsv2nodeop_opv_desc);
+#endif
int (**fifo_nfsv2nodeop_p)();
struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
@@ -192,8 +224,14 @@ struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
{ &vop_setattr_desc, nfs_setattr }, /* setattr */
{ &vop_read_desc, nfsfifo_read }, /* read */
{ &vop_write_desc, nfsfifo_write }, /* write */
+#ifdef HAS_VOPLEASE
+ { &vop_lease_desc, fifo_lease_check }, /* lease */
+#endif
{ &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
{ &vop_select_desc, fifo_select }, /* select */
+#ifdef HAS_VOPREVOKE
+ { &vop_revoke_desc, fifo_revoke }, /* revoke */
+#endif
{ &vop_mmap_desc, fifo_mmap }, /* mmap */
{ &vop_fsync_desc, nfs_fsync }, /* fsync */
{ &vop_seek_desc, fifo_seek }, /* seek */
@@ -227,15 +265,21 @@ struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
};
struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
+#ifdef __FreeBSD__
VNODEOP_SET(fifo_nfsv2nodeop_opv_desc);
+#endif
void nqnfs_clientlease();
+int nfs_commit();
+int nfs_removerpc();
+int nfs_renamerpc();
/*
* Global variables
*/
-extern u_long nfs_procids[NFS_NPROCS];
-extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
+extern u_long nfs_true, nfs_false;
+extern struct nfsstats nfsstats;
+extern nfstype nfsv3_type[9];
struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
int nfs_numasync = 0;
#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
@@ -261,9 +305,9 @@ nfs_null(vp, cred, procp)
/*
* nfs access vnode op.
- * For nfs, just return ok. File accesses may fail later.
- * For nqnfs, use the access rpc to check accessibility. If file modes are
- * changed on the server, accesses might still fail later.
+ * For nfs version 2, just return ok. File accesses may fail later.
+ * For nfs version 3, use the access rpc to check accessibility. If file modes
+ * are changed on the server, accesses might still fail later.
*/
int
nfs_access(ap)
@@ -277,36 +321,56 @@ nfs_access(ap)
register struct vnode *vp = ap->a_vp;
register u_long *tl;
register caddr_t cp;
- caddr_t bpos, dpos;
- int error = 0;
+ register int t1, t2;
+ caddr_t bpos, dpos, cp2;
+ int error = 0, attrflag;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ u_long mode, rmode;
+ int v3 = NFS_ISV3(vp);
/*
- * For nqnfs, do an access rpc, otherwise you are stuck emulating
+ * For nfs v3, do an access rpc, otherwise you are stuck emulating
* ufs_access() locally using the vattr. This may not be correct,
* since the server may apply other access criteria such as
* client uid-->server uid mapping that we do not know about, but
* this is better than just returning anything that is lying about
* in the cache.
*/
- if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
- nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
- nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
- nfsm_fhtom(vp);
- nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ if (v3) {
+ nfsstats.rpccnt[NFSPROC_ACCESS]++;
+ nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
+ nfsm_fhtom(vp, v3);
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
if (ap->a_mode & VREAD)
- *tl++ = nfs_true;
- else
- *tl++ = nfs_false;
- if (ap->a_mode & VWRITE)
- *tl++ = nfs_true;
- else
- *tl++ = nfs_false;
- if (ap->a_mode & VEXEC)
- *tl = nfs_true;
+ mode = NFSV3ACCESS_READ;
else
- *tl = nfs_false;
- nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
+ mode = 0;
+ if (vp->v_type == VDIR) {
+ if (ap->a_mode & VWRITE)
+ mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
+ NFSV3ACCESS_DELETE);
+ if (ap->a_mode & VEXEC)
+ mode |= NFSV3ACCESS_LOOKUP;
+ } else {
+ if (ap->a_mode & VWRITE)
+ mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
+ if (ap->a_mode & VEXEC)
+ mode |= NFSV3ACCESS_EXECUTE;
+ }
+ *tl = txdr_unsigned(mode);
+ nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
+ nfsm_postop_attr(vp, attrflag);
+ if (!error) {
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ rmode = fxdr_unsigned(u_long, *tl);
+ /*
+ * The NFS V3 spec does not clarify whether or not
+ * the returned access bits can be a superset of
+ * the ones requested, so...
+ */
+ if ((rmode & mode) != mode)
+ error = EACCES;
+ }
nfsm_reqdone;
return (error);
} else
@@ -337,14 +401,17 @@ nfs_open(ap)
int error;
if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
+{ printf("open eacces vtyp=%d\n",vp->v_type);
return (EACCES);
+}
/*
* Get a valid lease. If cached data is stale, flush it.
*/
if (nmp->nm_flag & NFSMNT_NQNFS) {
- if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
+ if (NQNFS_CKINVALID(vp, np, ND_READ)) {
do {
- error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
+ error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
+ ap->a_p);
} while (error == NQNFS_EXPIRED);
if (error)
return (error);
@@ -353,6 +420,7 @@ nfs_open(ap)
if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
ap->a_p, 1)) == EINTR)
return (error);
+ (void) vnode_pager_uncache(vp);
np->n_brev = np->n_lrev;
}
}
@@ -361,8 +429,10 @@ nfs_open(ap)
if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
ap->a_p, 1)) == EINTR)
return (error);
+ /* (void) vnode_pager_uncache(vp); */
np->n_attrstamp = 0;
- np->n_direofoffset = 0;
+ if (vp->v_type == VDIR)
+ np->n_direofoffset = 0;
error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
if (error)
return (error);
@@ -372,10 +442,12 @@ nfs_open(ap)
if (error)
return (error);
if (np->n_mtime != vattr.va_mtime.ts_sec) {
- np->n_direofoffset = 0;
+ if (vp->v_type == VDIR)
+ np->n_direofoffset = 0;
if ((error = nfs_vinvalbuf(vp, V_SAVE,
ap->a_cred, ap->a_p, 1)) == EINTR)
return (error);
+ /* (void) vnode_pager_uncache(vp); */
np->n_mtime = vattr.va_mtime.ts_sec;
}
}
@@ -387,7 +459,33 @@ nfs_open(ap)
/*
* nfs close vnode op
- * For reg files, invalidate any buffer cache entries.
+ * What an NFS client should do upon close after writing is a debatable issue.
+ * Most NFS clients push delayed writes to the server upon close, basically for
+ * two reasons:
+ * 1 - So that any write errors may be reported back to the client process
+ * doing the close system call. By far the two most likely errors are
+ * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
+ * 2 - To put a worst case upper bound on cache inconsistency between
+ * multiple clients for the file.
+ * There is also a consistency problem for Version 2 of the protocol w.r.t.
+ * not being able to tell if other clients are writing a file concurrently,
+ * since there is no way of knowing if the changed modify time in the reply
+ * is only due to the write for this client.
+ * (NFS Version 3 provides weak cache consistency data in the reply that
+ * should be sufficient to detect and handle this case.)
+ *
+ * The current code does the following:
+ * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
+ * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
+ * or commit them (this satisfies 1 and 2 except for the
+ * case where the server crashes after this close but
+ * before the commit RPC, which is felt to be "good
+ * enough". Changing the last argument to nfs_flush() to
+ * a 1 would force a commit operation, if it is felt a
+ * commit is necessary now.
+ * for NQNFS - do nothing now, since 2 is dealt with via leases and
+ * 1 should be dealt with via an fsync() system call for
+ * cases where write errors are important.
*/
/* ARGSUSED */
int
@@ -407,7 +505,10 @@ nfs_close(ap)
if (vp->v_type == VREG) {
if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
(np->n_flag & NMODIFIED)) {
- error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
+ if (NFS_ISV3(vp))
+ error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
+ else
+ error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
np->n_attrstamp = 0;
}
if (np->n_flag & NWRITEERR) {
@@ -433,9 +534,12 @@ nfs_getattr(ap)
register struct vnode *vp = ap->a_vp;
register struct nfsnode *np = VTONFS(vp);
register caddr_t cp;
+ register u_long *tl;
+ register int t1, t2;
caddr_t bpos, dpos;
int error = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ int v3 = NFS_ISV3(vp);
/*
* Update local times for special files.
@@ -448,10 +552,11 @@ nfs_getattr(ap)
if (nfs_getattrcache(vp, ap->a_vap) == 0)
return (0);
nfsstats.rpccnt[NFSPROC_GETATTR]++;
- nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
- nfsm_fhtom(vp);
+ nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
+ nfsm_fhtom(vp, v3);
nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
- nfsm_loadattr(vp, ap->a_vap);
+ if (!error)
+ nfsm_loadattr(vp, ap->a_vap);
nfsm_reqdone;
return (error);
}
@@ -469,92 +574,166 @@ nfs_setattr(ap)
struct proc *a_p;
} */ *ap;
{
- register struct nfsv2_sattr *sp;
- register caddr_t cp;
- register long t1;
- caddr_t bpos, dpos, cp2;
- u_long *tl;
- int error = 0, isnq;
- struct mbuf *mreq, *mrep, *md, *mb, *mb2;
register struct vnode *vp = ap->a_vp;
register struct nfsnode *np = VTONFS(vp);
register struct vattr *vap = ap->a_vap;
- u_quad_t frev, tsize = 0;
+ int error = 0;
+ u_quad_t tsize;
+#ifndef nolint
+ tsize = (u_quad_t)0;
+#endif
if (vap->va_size != VNOVAL) {
- switch (vp->v_type) {
- case VDIR:
- return (EISDIR);
- case VCHR:
- case VBLK:
+ switch (vp->v_type) {
+ case VDIR:
+ return (EISDIR);
+ case VCHR:
+ case VBLK:
if (vap->va_mtime.ts_sec == VNOVAL &&
vap->va_atime.ts_sec == VNOVAL &&
vap->va_mode == (u_short)VNOVAL &&
- vap->va_uid == VNOVAL &&
- vap->va_gid == VNOVAL)
+ vap->va_uid == (uid_t)VNOVAL &&
+ vap->va_gid == (gid_t)VNOVAL)
return (0);
- vap->va_size = VNOVAL;
- break;
- default:
- if (np->n_flag & NMODIFIED) {
- error = nfs_vinvalbuf(vp,
- vap->va_size ? V_SAVE : 0,
- ap->a_cred, ap->a_p, 1);
- if (error)
- return (error);
- }
- tsize = np->n_size;
- np->n_size = np->n_vattr.va_size = vap->va_size;
- vnode_pager_setsize(vp, (u_long)np->n_size);
- }
- } else if ((vap->va_mtime.ts_sec != VNOVAL ||
- vap->va_atime.ts_sec != VNOVAL) && (np->n_flag & NMODIFIED)) {
- error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
- if (error == EINTR)
- return (error);
+ vap->va_size = VNOVAL;
+ break;
+ default:
+ if (np->n_flag & NMODIFIED) {
+ if (vap->va_size == 0)
+ error = nfs_vinvalbuf(vp, 0,
+ ap->a_cred, ap->a_p, 1);
+ else
+ error = nfs_vinvalbuf(vp, V_SAVE,
+ ap->a_cred, ap->a_p, 1);
+ if (error)
+ return (error);
+ }
+ tsize = np->n_size;
+ np->n_size = np->n_vattr.va_size = vap->va_size;
+ vnode_pager_setsize(vp, (u_long)np->n_size);
+ };
+ } else if ((vap->va_mtime.ts_sec != VNOVAL ||
+ vap->va_atime.ts_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
+ vp->v_type == VREG &&
+ (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
+ ap->a_p, 1)) == EINTR)
+ return (error);
+ error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
+ if (error) {
+ np->n_size = np->n_vattr.va_size = tsize;
+ vnode_pager_setsize(vp, (u_long)np->n_size);
}
+ return (error);
+}
+
+/*
+ * Do an nfs setattr rpc.
+ */
+int
+nfs_setattrrpc(vp, vap, cred, procp)
+ register struct vnode *vp;
+ register struct vattr *vap;
+ struct ucred *cred;
+ struct proc *procp;
+{
+ register struct nfsv2_sattr *sp;
+ register caddr_t cp;
+ register long t1, t2;
+ caddr_t bpos, dpos, cp2;
+ u_long *tl;
+ int error = 0, wccflag = NFSV3_WCCRATTR;
+ struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ u_quad_t frev;
+ int v3 = NFS_ISV3(vp);
+
nfsstats.rpccnt[NFSPROC_SETATTR]++;
- isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
- nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
- nfsm_fhtom(vp);
- nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
- if (vap->va_mode == (u_short)-1)
- sp->sa_mode = VNOVAL;
- else
- sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
- if (vap->va_uid == (uid_t)-1)
- sp->sa_uid = VNOVAL;
- else
- sp->sa_uid = txdr_unsigned(vap->va_uid);
- if (vap->va_gid == (gid_t)-1)
- sp->sa_gid = VNOVAL;
- else
- sp->sa_gid = txdr_unsigned(vap->va_gid);
- if (isnq) {
- txdr_hyper(&vap->va_size, &sp->sa_nqsize);
- txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
- txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
- sp->sa_nqflags = txdr_unsigned(vap->va_flags);
- sp->sa_nqrdev = VNOVAL;
+ nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
+ nfsm_fhtom(vp, v3);
+ if (v3) {
+ if (vap->va_mode != (u_short)VNOVAL) {
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ *tl = txdr_unsigned(vap->va_mode);
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ }
+ if (vap->va_uid != (uid_t)VNOVAL) {
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ *tl = txdr_unsigned(vap->va_uid);
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ }
+ if (vap->va_gid != (gid_t)VNOVAL) {
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ *tl = txdr_unsigned(vap->va_gid);
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ }
+ if (vap->va_size != VNOVAL) {
+ nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ *tl++ = nfs_true;
+ txdr_hyper(&vap->va_size, tl);
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
+ }
+ if (vap->va_atime.ts_sec != VNOVAL) {
+ if (vap->va_atime.ts_sec != time.tv_sec) {
+ nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
+ txdr_nfsv3time(&vap->va_atime, tl);
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
+ }
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
+ }
+ if (vap->va_mtime.ts_sec != VNOVAL) {
+ if (vap->va_mtime.ts_sec != time.tv_sec) {
+ nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
+ txdr_nfsv3time(&vap->va_atime, tl);
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
+ }
+ } else {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
+ }
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ *tl = nfs_false;
} else {
- sp->sa_nfssize = txdr_unsigned(vap->va_size);
- txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
- txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
- }
- nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
- nfsm_loadattr(vp, (struct vattr *)0);
- if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
- nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
- fxdr_hyper(tl, &frev);
- if (frev > np->n_brev)
- np->n_brev = frev;
+ nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ if (vap->va_mode == (u_short)VNOVAL)
+ sp->sa_mode = VNOVAL;
+ else
+ sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
+ if (vap->va_uid == (uid_t)VNOVAL)
+ sp->sa_uid = VNOVAL;
+ else
+ sp->sa_uid = txdr_unsigned(vap->va_uid);
+ if (vap->va_gid == (gid_t)VNOVAL)
+ sp->sa_gid = VNOVAL;
+ else
+ sp->sa_gid = txdr_unsigned(vap->va_gid);
+ sp->sa_size = txdr_unsigned(vap->va_size);
+ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
+ txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
+ nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
+ if (v3) {
+ nfsm_wcc_data(vp, wccflag);
+ } else
+ nfsm_loadattr(vp, (struct vattr *)0);
nfsm_reqdone;
- if (error) {
- np->n_size = np->n_vattr.va_size = tsize;
- vnode_pager_setsize(vp, (u_long)np->n_size);
- }
return (error);
}
@@ -576,23 +755,20 @@ nfs_lookup(ap)
register struct vnode *dvp = ap->a_dvp;
register struct vnode **vpp = ap->a_vpp;
register int flags = cnp->cn_flags;
- register struct vnode *vdp;
+ register struct vnode *newvp;
register u_long *tl;
register caddr_t cp;
register long t1, t2;
struct nfsmount *nmp;
caddr_t bpos, dpos, cp2;
- time_t reqtime = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- struct vnode *newvp;
long len;
- nfsv2fh_t *fhp;
+ nfsfh_t *fhp;
struct nfsnode *np;
- int lockparent, wantparent, error = 0;
- int nqlflag = 0, cachable = 0;
- u_quad_t frev;
+ int lockparent, wantparent, error = 0, attrflag, fhsize;
+ int v3 = NFS_ISV3(dvp);
- *vpp = NULL;
+ *vpp = NULLVP;
if (dvp->v_type != VDIR)
return (ENOTDIR);
lockparent = flags & LOCKPARENT;
@@ -603,161 +779,141 @@ nfs_lookup(ap)
struct vattr vattr;
int vpid;
- vdp = *vpp;
- vpid = vdp->v_id;
+ newvp = *vpp;
+ vpid = newvp->v_id;
/*
* See the comment starting `Step through' in ufs/ufs_lookup.c
* for an explanation of the locking protocol
*/
- if (dvp == vdp) {
- VREF(vdp);
+ if (dvp == newvp) {
+ VREF(newvp);
error = 0;
- } else
- error = vget(vdp, 1);
+ } else if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp);
+ error = vget(newvp, 1);
+ if (!error && lockparent && (flags & ISLASTCN))
+ error = VOP_LOCK(dvp);
+ } else {
+ error = vget(newvp, 1);
+ if (!lockparent || error || !(flags & ISLASTCN))
+ VOP_UNLOCK(dvp);
+ }
if (!error) {
- if (vpid == vdp->v_id) {
- if (nmp->nm_flag & NFSMNT_NQNFS) {
- if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
- nfsstats.lookupcache_hits++;
- if (cnp->cn_nameiop != LOOKUP &&
- (flags & ISLASTCN))
- cnp->cn_flags |= SAVENAME;
- return (0);
- } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
- if (np->n_lrev != np->n_brev ||
- (np->n_flag & NMODIFIED)) {
- np->n_direofoffset = 0;
- cache_purge(dvp);
- error = nfs_vinvalbuf(dvp, 0,
- cnp->cn_cred, cnp->cn_proc,
- 1);
- if (error == EINTR)
- return (error);
- np->n_brev = np->n_lrev;
- } else {
- nfsstats.lookupcache_hits++;
- if (cnp->cn_nameiop != LOOKUP &&
- (flags & ISLASTCN))
- cnp->cn_flags |= SAVENAME;
- return (0);
- }
- }
- } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
- vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
+ if (vpid == newvp->v_id) {
+ if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
+ && vattr.va_ctime.ts_sec == VTONFS(newvp)->n_ctime) {
nfsstats.lookupcache_hits++;
if (cnp->cn_nameiop != LOOKUP &&
(flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
return (0);
}
- cache_purge(vdp);
+ cache_purge(newvp);
}
- vrele(vdp);
+ vput(newvp);
+ if (lockparent && dvp != newvp && (flags & ISLASTCN))
+ VOP_UNLOCK(dvp);
}
+ error = VOP_LOCK(dvp);
+ if (error)
+ return (error);
*vpp = NULLVP;
}
error = 0;
+ newvp = NULLVP;
nfsstats.lookupcache_misses++;
nfsstats.rpccnt[NFSPROC_LOOKUP]++;
len = cnp->cn_namelen;
- nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
-
- /*
- * For nqnfs optionally piggyback a getlease request for the name
- * being looked up.
- */
- if (nmp->nm_flag & NFSMNT_NQNFS) {
- nfsm_build(tl, u_long *, NFSX_UNSIGNED);
- if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
- ((cnp->cn_flags & MAKEENTRY) &&
- (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
- *tl = txdr_unsigned(nmp->nm_leaseterm);
- else
- *tl = 0;
- }
- nfsm_fhtom(dvp);
+ nfsm_reqhead(dvp, NFSPROC_LOOKUP,
+ NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+ nfsm_fhtom(dvp, v3);
nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
- reqtime = time.tv_sec;
nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
-nfsmout:
if (error) {
- if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
- (flags & ISLASTCN) && error == ENOENT)
- error = EJUSTRETURN;
- if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
- cnp->cn_flags |= SAVENAME;
- return (error);
- }
- if (nmp->nm_flag & NFSMNT_NQNFS) {
- nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
- if (*tl) {
- nqlflag = fxdr_unsigned(int, *tl);
- nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
- cachable = fxdr_unsigned(int, *tl++);
- reqtime += fxdr_unsigned(int, *tl++);
- fxdr_hyper(tl, &frev);
- } else
- nqlflag = 0;
+ nfsm_postop_attr(dvp, attrflag);
+ m_freem(mrep);
+ goto nfsmout;
}
- nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
+ nfsm_getfh(fhp, fhsize, v3);
/*
* Handle RENAME case...
*/
if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
- if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+ if (NFS_CMPFH(np, fhp, fhsize)) {
m_freem(mrep);
return (EISDIR);
}
- error = nfs_nget(dvp->v_mount, fhp, &np);
- if (error) {
+ if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
m_freem(mrep);
return (error);
}
newvp = NFSTOV(np);
- error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr*)0);
- if (error) {
- vrele(newvp);
- m_freem(mrep);
- return (error);
- }
+ if (v3) {
+ nfsm_postop_attr(newvp, attrflag);
+ nfsm_postop_attr(dvp, attrflag);
+ } else
+ nfsm_loadattr(newvp, (struct vattr *)0);
*vpp = newvp;
m_freem(mrep);
cnp->cn_flags |= SAVENAME;
+ if (!lockparent)
+ VOP_UNLOCK(dvp);
return (0);
}
- if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+ if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp);
+ error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
+ if (error) {
+ VOP_LOCK(dvp);
+ return (error);
+ }
+ newvp = NFSTOV(np);
+ if (lockparent && (flags & ISLASTCN) &&
+ (error = VOP_LOCK(dvp))) {
+ vput(newvp);
+ return (error);
+ }
+ } else if (NFS_CMPFH(np, fhp, fhsize)) {
VREF(dvp);
newvp = dvp;
} else {
- error = nfs_nget(dvp->v_mount, fhp, &np);
- if (error) {
+ if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
m_freem(mrep);
return (error);
}
+ if (!lockparent || !(flags & ISLASTCN))
+ VOP_UNLOCK(dvp);
newvp = NFSTOV(np);
}
- error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0);
- if (error) {
- vrele(newvp);
- m_freem(mrep);
- return (error);
- }
- m_freem(mrep);
- *vpp = newvp;
+ if (v3) {
+ nfsm_postop_attr(newvp, attrflag);
+ nfsm_postop_attr(dvp, attrflag);
+ } else
+ nfsm_loadattr(newvp, (struct vattr *)0);
if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
if ((cnp->cn_flags & MAKEENTRY) &&
(cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
- if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
- np->n_ctime = np->n_vattr.va_ctime.ts_sec;
- else if (nqlflag && reqtime > time.tv_sec)
- nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
- frev);
- cache_enter(dvp, *vpp, cnp);
+ np->n_ctime = np->n_vattr.va_ctime.ts_sec;
+ cache_enter(dvp, newvp, cnp);
}
- return (0);
+ *vpp = newvp;
+ nfsm_reqdone;
+ if (error) {
+ if (newvp != NULLVP)
+ vrele(newvp);
+ if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
+ (flags & ISLASTCN) && error == ENOENT) {
+ if (!lockparent)
+ VOP_UNLOCK(dvp);
+ error = EJUSTRETURN;
+ }
+ if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
+ cnp->cn_flags |= SAVENAME;
+ }
+ return (error);
}
/*
@@ -810,18 +966,22 @@ nfs_readlinkrpc(vp, uiop, cred)
{
register u_long *tl;
register caddr_t cp;
- register long t1;
+ register long t1, t2;
caddr_t bpos, dpos, cp2;
- int error = 0;
+ int error = 0, len, attrflag;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- long len;
+ int v3 = NFS_ISV3(vp);
nfsstats.rpccnt[NFSPROC_READLINK]++;
- nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
- nfsm_fhtom(vp);
+ nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
+ nfsm_fhtom(vp, v3);
nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
- nfsm_strsiz(len, NFS_MAXPATHLEN);
- nfsm_mtouio(uiop, len);
+ if (v3)
+ nfsm_postop_attr(vp, attrflag);
+ if (!error) {
+ nfsm_strsiz(len, NFS_MAXPATHLEN);
+ nfsm_mtouio(uiop, len);
+ }
nfsm_reqdone;
return (error);
}
@@ -838,25 +998,27 @@ nfs_readrpc(vp, uiop, cred)
{
register u_long *tl;
register caddr_t cp;
- register long t1;
+ register long t1, t2;
caddr_t bpos, dpos, cp2;
- int error = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
struct nfsmount *nmp;
- long len, retlen, tsiz;
+ int error = 0, len, retlen, tsiz, eof, attrflag;
+ int v3 = NFS_ISV3(vp);
+#ifndef nolint
+ eof = 0;
+#endif
nmp = VFSTONFS(vp->v_mount);
tsiz = uiop->uio_resid;
- if (uiop->uio_offset + tsiz > 0xffffffff &&
- (nmp->nm_flag & NFSMNT_NQNFS) == 0)
+ if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
return (EFBIG);
while (tsiz > 0) {
nfsstats.rpccnt[NFSPROC_READ]++;
len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
- nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
- nfsm_fhtom(vp);
- nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
- if (nmp->nm_flag & NFSMNT_NQNFS) {
+ nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
+ nfsm_fhtom(vp, v3);
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
+ if (v3) {
txdr_hyper(&uiop->uio_offset, tl);
*(tl + 2) = txdr_unsigned(len);
} else {
@@ -865,14 +1027,25 @@ nfs_readrpc(vp, uiop, cred)
*tl = 0;
}
nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
- nfsm_loadattr(vp, (struct vattr *)0);
+ if (v3) {
+ nfsm_postop_attr(vp, attrflag);
+ if (error) {
+ m_freem(mrep);
+ goto nfsmout;
+ }
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ eof = fxdr_unsigned(int, *(tl + 1));
+ } else
+ nfsm_loadattr(vp, (struct vattr *)0);
nfsm_strsiz(retlen, nmp->nm_rsize);
nfsm_mtouio(uiop, retlen);
m_freem(mrep);
- if (retlen < len)
+ tsiz -= retlen;
+ if (v3) {
+ if (eof || retlen == 0)
+ tsiz = 0;
+ } else if (retlen < len)
tsiz = 0;
- else
- tsiz -= len;
}
nfsmout:
return (error);
@@ -882,150 +1055,227 @@ nfsmout:
* nfs write call
*/
int
-nfs_writerpc(vp, uiop, cred, ioflags)
+nfs_writerpc(vp, uiop, cred, iomode, must_commit)
register struct vnode *vp;
- struct uio *uiop;
+ register struct uio *uiop;
struct ucred *cred;
- int ioflags;
+ int *iomode, *must_commit;
{
register u_long *tl;
register caddr_t cp;
- register long t1;
+ register int t1, t2, backup;
caddr_t bpos, dpos, cp2;
- int error = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- struct nfsmount *nmp;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
struct nfsnode *np = VTONFS(vp);
u_quad_t frev;
- long len, tsiz;
+ int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
+ int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
- nmp = VFSTONFS(vp->v_mount);
+#ifndef DIAGNOSTIC
+ if (uiop->uio_iovcnt != 1)
+ panic("nfs: writerpc iovcnt > 1");
+#endif
+ *must_commit = 0;
tsiz = uiop->uio_resid;
- if (uiop->uio_offset + tsiz > 0xffffffff &&
- (nmp->nm_flag & NFSMNT_NQNFS) == 0)
+ if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
return (EFBIG);
while (tsiz > 0) {
nfsstats.rpccnt[NFSPROC_WRITE]++;
len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
nfsm_reqhead(vp, NFSPROC_WRITE,
- NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
- nfsm_fhtom(vp);
- nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
- if (nmp->nm_flag & NFSMNT_NQNFS) {
+ NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
+ nfsm_fhtom(vp, v3);
+ if (v3) {
+ nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
txdr_hyper(&uiop->uio_offset, tl);
tl += 2;
-#ifdef notyet
- if (ioflags & IO_APPEND)
- *tl++ = txdr_unsigned(1);
- else
-#endif
- *tl++ = 0;
+ *tl++ = txdr_unsigned(len);
+ *tl++ = txdr_unsigned(*iomode);
} else {
+ nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
*++tl = txdr_unsigned(uiop->uio_offset);
tl += 2;
}
*tl = txdr_unsigned(len);
nfsm_uiotom(uiop, len);
nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
- nfsm_loadattr(vp, (struct vattr *)0);
- if (nmp->nm_flag & NFSMNT_MYWRITE)
- VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
- else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
- NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
- nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
- fxdr_hyper(tl, &frev);
- if (frev > np->n_brev)
- np->n_brev = frev;
- }
+ if (v3) {
+ wccflag = NFSV3_WCCCHK;
+ nfsm_wcc_data(vp, wccflag);
+ if (!error) {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
+ NFSX_V3WRITEVERF);
+ rlen = fxdr_unsigned(int, *tl++);
+ if (rlen == 0) {
+ error = NFSERR_IO;
+ break;
+ } else if (rlen < len) {
+ backup = len - rlen;
+ uiop->uio_iov->iov_base -= backup;
+ uiop->uio_iov->iov_len += backup;
+ uiop->uio_offset -= backup;
+ uiop->uio_resid += backup;
+ len = rlen;
+ }
+ commit = fxdr_unsigned(int, *tl++);
+
+ /*
+ * Return the lowest committment level
+ * obtained by any of the RPCs.
+ */
+ if (committed == NFSV3WRITE_FILESYNC)
+ committed = commit;
+ else if (committed == NFSV3WRITE_DATASYNC &&
+ commit == NFSV3WRITE_UNSTABLE)
+ committed = commit;
+ if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
+ bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
+ NFSX_V3WRITEVERF);
+ nmp->nm_flag |= NFSMNT_HASWRITEVERF;
+ } else if (bcmp((caddr_t)tl,
+ (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
+ *must_commit = 1;
+ bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
+ NFSX_V3WRITEVERF);
+ }
+ }
+ } else
+ nfsm_loadattr(vp, (struct vattr *)0);
+ if (wccflag)
+ VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
m_freem(mrep);
tsiz -= len;
}
nfsmout:
+ *iomode = committed;
if (error)
uiop->uio_resid = tsiz;
return (error);
}
/*
- * nfs mknod call
- * This is a kludge. Use a create rpc but with the IFMT bits of the mode
- * set to specify the file type and the size field for rdev.
+ * nfs mknod rpc
+ * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
+ * mode set to specify the file type and the size field for rdev.
*/
-/* ARGSUSED */
int
-nfs_mknod(ap)
- struct vop_mknod_args /* {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- } */ *ap;
+nfs_mknodrpc(dvp, vpp, cnp, vap)
+ register struct vnode *dvp;
+ register struct vnode **vpp;
+ register struct componentname *cnp;
+ register struct vattr *vap;
{
- register struct vnode *dvp = ap->a_dvp;
- register struct vattr *vap = ap->a_vap;
- register struct componentname *cnp = ap->a_cnp;
register struct nfsv2_sattr *sp;
+ register struct nfsv3_sattr *sp3;
register u_long *tl;
register caddr_t cp;
register long t1, t2;
- struct vnode *newvp = 0;
+ struct vnode *newvp = (struct vnode *)0;
+ struct nfsnode *np = (struct nfsnode *)0;
struct vattr vattr;
char *cp2;
caddr_t bpos, dpos;
- int error = 0, isnq;
+ int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
u_long rdev;
+ int v3 = NFS_ISV3(dvp);
- isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
if (vap->va_type == VCHR || vap->va_type == VBLK)
rdev = txdr_unsigned(vap->va_rdev);
- else if (vap->va_type == VFIFO)
+ else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
rdev = 0xffffffff;
else {
VOP_ABORTOP(dvp, cnp);
vput(dvp);
return (EOPNOTSUPP);
}
- error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc);
- if (error) {
+ if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
VOP_ABORTOP(dvp, cnp);
vput(dvp);
return (error);
}
- newvp = NULLVP;
- nfsstats.rpccnt[NFSPROC_CREATE]++;
- nfsm_reqhead(dvp, NFSPROC_CREATE,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
- nfsm_fhtom(dvp);
+ nfsstats.rpccnt[NFSPROC_MKNOD]++;
+ nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
+ + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+ nfsm_fhtom(dvp, v3);
nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
- sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
- sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
- sp->sa_gid = txdr_unsigned(vattr.va_gid);
- if (isnq) {
- sp->sa_nqrdev = rdev;
- sp->sa_nqflags = 0;
- txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
- txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
+ if (v3) {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
+ *tl++ = vtonfsv3_type(vap->va_type);
+ sp3 = (struct nfsv3_sattr *)tl;
+ nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
+ if (vap->va_type == VCHR || vap->va_type == VBLK) {
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ *tl++ = txdr_unsigned(major(vap->va_rdev));
+ *tl = txdr_unsigned(minor(vap->va_rdev));
+ }
} else {
- sp->sa_nfssize = rdev;
- txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
- txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
+ nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
+ sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
+ sp->sa_gid = txdr_unsigned(vattr.va_gid);
+ sp->sa_size = rdev;
+ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
+ txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
- nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
- nfsm_mtofh(dvp, newvp);
+ nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
+ if (!error) {
+ nfsm_mtofh(dvp, newvp, v3, gotvp);
+ if (!gotvp) {
+ if (newvp) {
+ vput(newvp);
+ newvp = (struct vnode *)0;
+ }
+ error = nfs_lookitup(dvp, cnp->cn_nameptr,
+ cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
+ if (!error)
+ newvp = NFSTOV(np);
+ }
+ }
+ if (v3)
+ nfsm_wcc_data(dvp, wccflag);
nfsm_reqdone;
- if (!error && (cnp->cn_flags & MAKEENTRY))
- cache_enter(dvp, newvp, cnp);
+ if (error) {
+ if (newvp)
+ vput(newvp);
+ } else {
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, newvp, cnp);
+ *vpp = newvp;
+ }
FREE(cnp->cn_pnbuf, M_NAMEI);
VTONFS(dvp)->n_flag |= NMODIFIED;
- VTONFS(dvp)->n_attrstamp = 0;
- vrele(dvp);
- if (newvp != NULLVP)
- vrele(newvp);
+ if (!wccflag)
+ VTONFS(dvp)->n_attrstamp = 0;
+ vput(dvp);
+ return (error);
+}
+
+/*
+ * nfs mknod vop
+ * just call nfs_mknodrpc() to do the work.
+ */
+/* ARGSUSED */
+int
+nfs_mknod(ap)
+ struct vop_mknod_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ struct vnode *newvp;
+ int error;
+
+ error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
+ if (!error)
+ vput(newvp);
return (error);
}
+static u_long create_verf;
/*
* nfs file create call
*/
@@ -1042,52 +1292,98 @@ nfs_create(ap)
register struct vattr *vap = ap->a_vap;
register struct componentname *cnp = ap->a_cnp;
register struct nfsv2_sattr *sp;
+ register struct nfsv3_sattr *sp3;
register u_long *tl;
register caddr_t cp;
register long t1, t2;
+ struct nfsnode *np = (struct nfsnode *)0;
+ struct vnode *newvp = (struct vnode *)0;
caddr_t bpos, dpos, cp2;
- int error = 0, isnq;
+ int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
struct vattr vattr;
+ int v3 = NFS_ISV3(dvp);
- error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc);
- if (error) {
+ /*
+ * Oops, not for me..
+ */
+ if (vap->va_type == VSOCK)
+ return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
+
+ if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
VOP_ABORTOP(dvp, cnp);
vput(dvp);
return (error);
}
+ if (vap->va_vaflags & VA_EXCLUSIVE)
+ fmode |= O_EXCL;
+again:
nfsstats.rpccnt[NFSPROC_CREATE]++;
- isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
- nfsm_reqhead(dvp, NFSPROC_CREATE,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
- nfsm_fhtom(dvp);
+ nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
+ nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+ nfsm_fhtom(dvp, v3);
nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
- sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
- sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
- sp->sa_gid = txdr_unsigned(vattr.va_gid);
- if (isnq) {
- u_quad_t qval = 0;
-
- txdr_hyper(&qval, &sp->sa_nqsize);
- sp->sa_nqflags = 0;
- sp->sa_nqrdev = -1;
- txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
- txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
+ if (v3) {
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED);
+ if (fmode & O_EXCL) {
+ *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
+ nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
+ if (in_ifaddr)
+ *tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr;
+ else
+ *tl++ = create_verf;
+ *tl = ++create_verf;
+ } else {
+ *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
+ nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
+ sp3 = (struct nfsv3_sattr *)tl;
+ nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
+ }
} else {
- sp->sa_nfssize = 0;
- txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
- txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
+ nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
+ sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
+ sp->sa_gid = txdr_unsigned(vattr.va_gid);
+ sp->sa_size = 0;
+ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
+ txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
- nfsm_mtofh(dvp, *ap->a_vpp);
+ if (!error) {
+ nfsm_mtofh(dvp, newvp, v3, gotvp);
+ if (!gotvp) {
+ if (newvp) {
+ vput(newvp);
+ newvp = (struct vnode *)0;
+ }
+ error = nfs_lookitup(dvp, cnp->cn_nameptr,
+ cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
+ if (!error)
+ newvp = NFSTOV(np);
+ }
+ }
+ if (v3)
+ nfsm_wcc_data(dvp, wccflag);
nfsm_reqdone;
- if (!error && (cnp->cn_flags & MAKEENTRY))
- cache_enter(dvp, *ap->a_vpp, cnp);
+ if (error) {
+ if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
+ fmode &= ~O_EXCL;
+ goto again;
+ }
+ if (newvp)
+ vput(newvp);
+ } else if (v3 && (fmode & O_EXCL))
+ error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
+ if (!error) {
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, newvp, cnp);
+ *ap->a_vpp = newvp;
+ }
FREE(cnp->cn_pnbuf, M_NAMEI);
VTONFS(dvp)->n_flag |= NMODIFIED;
- VTONFS(dvp)->n_attrstamp = 0;
- vrele(dvp);
+ if (!wccflag)
+ VTONFS(dvp)->n_attrstamp = 0;
+ vput(dvp);
return (error);
}
@@ -1122,22 +1418,17 @@ nfs_remove(ap)
int error = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
struct vattr vattr;
+ int v3 = NFS_ISV3(dvp);
- if (vp->v_usecount > 1) {
- if (!np->n_sillyrename)
- error = nfs_sillyrename(dvp, vp, cnp);
- else if (VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc)
- == 0 && vattr.va_nlink > 1)
- /*
- * If we already have a silly name but there are more
- * than one links, just proceed with the NFS remove
- * request, as the bits will remain available (modulo
- * network races). This avoids silently ignoring the
- * attempted removal of a non-silly entry.
- */
- goto doit;
- } else {
- doit:
+#ifndef DIAGNOSTIC
+ if ((cnp->cn_flags & HASBUF) == 0)
+ panic("nfs_remove: no name");
+ if (vp->v_usecount < 1)
+ panic("nfs_remove: bad v_usecount");
+#endif
+ if (vp->v_usecount == 1 || (np->n_sillyrename &&
+ VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
+ vattr.va_nlink > 1)) {
/*
* Purge the name cache so that the chance of a lookup for
* the name succeeding while the remove is in progress is
@@ -1147,23 +1438,14 @@ nfs_remove(ap)
*/
cache_purge(vp);
/*
- * Throw away biocache buffers. Mainly to avoid
- * unnecessary delayed writes.
+ * throw away biocache buffers, mainly to avoid
+ * unnecessary delayed writes later.
*/
error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
- if (error == EINTR)
- return (error);
/* Do the rpc */
- nfsstats.rpccnt[NFSPROC_REMOVE]++;
- nfsm_reqhead(dvp, NFSPROC_REMOVE,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
- nfsm_fhtom(dvp);
- nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
- nfsm_reqdone;
- FREE(cnp->cn_pnbuf, M_NAMEI);
- VTONFS(dvp)->n_flag |= NMODIFIED;
- VTONFS(dvp)->n_attrstamp = 0;
+ if (error != EINTR)
+ error = nfs_removerpc(dvp, cnp->cn_nameptr,
+ cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
/*
* Kludge City: If the first reply to the remove rpc is lost..
* the reply to the retransmitted request will be ENOENT
@@ -1172,10 +1454,15 @@ nfs_remove(ap)
*/
if (error == ENOENT)
error = 0;
- }
+ } else if (!np->n_sillyrename)
+ error = nfs_sillyrename(dvp, vp, cnp);
+ FREE(cnp->cn_pnbuf, M_NAMEI);
np->n_attrstamp = 0;
- vrele(dvp);
- vrele(vp);
+ vput(dvp);
+ if (vp == dvp)
+ vrele(vp);
+ else
+ vput(vp);
return (error);
}
@@ -1186,22 +1473,42 @@ int
nfs_removeit(sp)
register struct sillyrename *sp;
{
+
+ return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
+ (struct proc *)0));
+}
+
+/*
+ * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
+ */
+int
+nfs_removerpc(dvp, name, namelen, cred, proc)
+ register struct vnode *dvp;
+ char *name;
+ int namelen;
+ struct ucred *cred;
+ struct proc *proc;
+{
register u_long *tl;
register caddr_t cp;
- register long t2;
- caddr_t bpos, dpos;
- int error = 0;
+ register long t1, t2;
+ caddr_t bpos, dpos, cp2;
+ int error = 0, wccflag = NFSV3_WCCRATTR;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ int v3 = NFS_ISV3(dvp);
nfsstats.rpccnt[NFSPROC_REMOVE]++;
- nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
- nfsm_fhtom(sp->s_dvp);
- nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
- nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
+ nfsm_reqhead(dvp, NFSPROC_REMOVE,
+ NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
+ nfsm_fhtom(dvp, v3);
+ nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
+ nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
+ if (v3)
+ nfsm_wcc_data(dvp, wccflag);
nfsm_reqdone;
- VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
- VTONFS(sp->s_dvp)->n_attrstamp = 0;
+ VTONFS(dvp)->n_flag |= NMODIFIED;
+ if (!wccflag)
+ VTONFS(dvp)->n_attrstamp = 0;
return (error);
}
@@ -1225,13 +1532,13 @@ nfs_rename(ap)
register struct vnode *tdvp = ap->a_tdvp;
register struct componentname *tcnp = ap->a_tcnp;
register struct componentname *fcnp = ap->a_fcnp;
- register u_long *tl;
- register caddr_t cp;
- register long t2;
- caddr_t bpos, dpos;
- int error = 0;
- struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ int error;
+#ifndef DIAGNOSTIC
+ if ((tcnp->cn_flags & HASBUF) == 0 ||
+ (fcnp->cn_flags & HASBUF) == 0)
+ panic("nfs_rename: no name");
+#endif
/* Check for cross-device rename */
if ((fvp->v_mount != tdvp->v_mount) ||
(tvp && (fvp->v_mount != tvp->v_mount))) {
@@ -1239,21 +1546,20 @@ nfs_rename(ap)
goto out;
}
+ /*
+ * If the tvp exists and is in use, sillyrename it before doing the
+ * rename of the new file over it.
+ */
+ if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
+ !nfs_sillyrename(tdvp, tvp, tcnp)) {
+ vrele(tvp);
+ tvp = NULL;
+ }
+
+ error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
+ tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
+ tcnp->cn_proc);
- nfsstats.rpccnt[NFSPROC_RENAME]++;
- nfsm_reqhead(fdvp, NFSPROC_RENAME,
- (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
- nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
- nfsm_fhtom(fdvp);
- nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_fhtom(tdvp);
- nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
- nfsm_reqdone;
- VTONFS(fdvp)->n_flag |= NMODIFIED;
- VTONFS(fdvp)->n_attrstamp = 0;
- VTONFS(tdvp)->n_flag |= NMODIFIED;
- VTONFS(tdvp)->n_attrstamp = 0;
if (fvp->v_type == VDIR) {
if (tvp != NULL && tvp->v_type == VDIR)
cache_purge(tdvp);
@@ -1285,26 +1591,52 @@ nfs_renameit(sdvp, scnp, sp)
struct componentname *scnp;
register struct sillyrename *sp;
{
+ return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
+ sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
+}
+
+/*
+ * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
+ */
+int
+nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
+ register struct vnode *fdvp;
+ char *fnameptr;
+ int fnamelen;
+ register struct vnode *tdvp;
+ char *tnameptr;
+ int tnamelen;
+ struct ucred *cred;
+ struct proc *proc;
+{
register u_long *tl;
register caddr_t cp;
- register long t2;
- caddr_t bpos, dpos;
- int error = 0;
+ register long t1, t2;
+ caddr_t bpos, dpos, cp2;
+ int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ int v3 = NFS_ISV3(fdvp);
nfsstats.rpccnt[NFSPROC_RENAME]++;
- nfsm_reqhead(sdvp, NFSPROC_RENAME,
- (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
- nfsm_rndup(sp->s_namlen));
- nfsm_fhtom(sdvp);
- nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_fhtom(sdvp);
- nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
- nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
+ nfsm_reqhead(fdvp, NFSPROC_RENAME,
+ (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
+ nfsm_rndup(tnamelen));
+ nfsm_fhtom(fdvp, v3);
+ nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
+ nfsm_fhtom(tdvp, v3);
+ nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
+ nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
+ if (v3) {
+ nfsm_wcc_data(fdvp, fwccflag);
+ nfsm_wcc_data(tdvp, twccflag);
+ }
nfsm_reqdone;
- FREE(scnp->cn_pnbuf, M_NAMEI);
- VTONFS(sdvp)->n_flag |= NMODIFIED;
- VTONFS(sdvp)->n_attrstamp = 0;
+ VTONFS(fdvp)->n_flag |= NMODIFIED;
+ VTONFS(tdvp)->n_flag |= NMODIFIED;
+ if (!fwccflag)
+ VTONFS(fdvp)->n_attrstamp = 0;
+ if (!twccflag)
+ VTONFS(tdvp)->n_attrstamp = 0;
return (error);
}
@@ -1319,22 +1651,32 @@ nfs_link(ap)
struct componentname *a_cnp;
} */ *ap;
{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+ /*
+ * Since the args are reversed in the VOP_LINK() calls,
+ * switch them back. Argh!
+ */
+ register struct vnode *vp = ap->a_tdvp;
+ register struct vnode *tdvp = ap->a_vp;
+#else
register struct vnode *vp = ap->a_vp;
register struct vnode *tdvp = ap->a_tdvp;
+#endif
register struct componentname *cnp = ap->a_cnp;
register u_long *tl;
register caddr_t cp;
- register long t2;
- caddr_t bpos, dpos;
- int error = 0;
+ register long t1, t2;
+ caddr_t bpos, dpos, cp2;
+ int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ int v3 = NFS_ISV3(vp);
if (vp->v_mount != tdvp->v_mount) {
/*VOP_ABORTOP(vp, cnp);*/
if (tdvp == vp)
- vrele(vp);
+ vrele(tdvp);
else
- vput(vp);
+ vput(tdvp);
return (EXDEV);
}
@@ -1343,21 +1685,27 @@ nfs_link(ap)
* doesn't get "out of sync" with the server.
* XXX There should be a better way!
*/
- VOP_FSYNC(tdvp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
+ VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
nfsstats.rpccnt[NFSPROC_LINK]++;
- nfsm_reqhead(tdvp, NFSPROC_LINK,
- NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
- nfsm_fhtom(tdvp);
- nfsm_fhtom(vp);
+ nfsm_reqhead(vp, NFSPROC_LINK,
+ NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+ nfsm_fhtom(vp, v3);
+ nfsm_fhtom(tdvp, v3);
nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
- nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
+ nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
+ if (v3) {
+ nfsm_postop_attr(vp, attrflag);
+ nfsm_wcc_data(tdvp, wccflag);
+ }
nfsm_reqdone;
FREE(cnp->cn_pnbuf, M_NAMEI);
- VTONFS(tdvp)->n_attrstamp = 0;
- VTONFS(vp)->n_flag |= NMODIFIED;
- VTONFS(vp)->n_attrstamp = 0;
- vrele(vp);
+ VTONFS(tdvp)->n_flag |= NMODIFIED;
+ if (!attrflag)
+ VTONFS(vp)->n_attrstamp = 0;
+ if (!wccflag)
+ VTONFS(tdvp)->n_attrstamp = 0;
+ vput(tdvp);
/*
* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
*/
@@ -1369,7 +1717,6 @@ nfs_link(ap)
/*
* nfs symbolic link create call
*/
-/* start here */
int
nfs_symlink(ap)
struct vop_symlink_args /* {
@@ -1384,43 +1731,51 @@ nfs_symlink(ap)
register struct vattr *vap = ap->a_vap;
register struct componentname *cnp = ap->a_cnp;
register struct nfsv2_sattr *sp;
+ register struct nfsv3_sattr *sp3;
register u_long *tl;
register caddr_t cp;
- register long t2;
- caddr_t bpos, dpos;
- int slen, error = 0, isnq;
+ register long t1, t2;
+ caddr_t bpos, dpos, cp2;
+ int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ struct vnode *newvp = (struct vnode *)0;
+ int v3 = NFS_ISV3(dvp);
nfsstats.rpccnt[NFSPROC_SYMLINK]++;
slen = strlen(ap->a_target);
- isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
- nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
- nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
- nfsm_fhtom(dvp);
+ nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
+ nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
+ nfsm_fhtom(dvp, v3);
nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+ if (v3) {
+ nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
+ nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
+ cnp->cn_cred->cr_gid);
+ }
nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
- nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
- sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
- sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
- sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
- if (isnq) {
- quad_t qval = -1;
-
- txdr_hyper(&qval, &sp->sa_nqsize);
- sp->sa_nqflags = 0;
- txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
- txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
- } else {
- sp->sa_nfssize = -1;
- txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
- txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
+ if (!v3) {
+ nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
+ sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
+ sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
+ sp->sa_size = -1;
+ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
+ txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
+ if (v3) {
+ if (!error)
+ nfsm_mtofh(dvp, newvp, v3, gotvp);
+ nfsm_wcc_data(dvp, wccflag);
+ }
nfsm_reqdone;
+ if (newvp)
+ vput(newvp);
FREE(cnp->cn_pnbuf, M_NAMEI);
VTONFS(dvp)->n_flag |= NMODIFIED;
- VTONFS(dvp)->n_attrstamp = 0;
- vrele(dvp);
+ if (!wccflag)
+ VTONFS(dvp)->n_attrstamp = 0;
+ vput(dvp);
/*
* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
*/
@@ -1444,76 +1799,78 @@ nfs_mkdir(ap)
register struct vnode *dvp = ap->a_dvp;
register struct vattr *vap = ap->a_vap;
register struct componentname *cnp = ap->a_cnp;
- register struct vnode **vpp = ap->a_vpp;
register struct nfsv2_sattr *sp;
+ register struct nfsv3_sattr *sp3;
register u_long *tl;
register caddr_t cp;
register long t1, t2;
register int len;
+ struct nfsnode *np = (struct nfsnode *)0;
+ struct vnode *newvp = (struct vnode *)0;
caddr_t bpos, dpos, cp2;
- int error = 0, firsttry = 1, isnq;
+ nfsfh_t *fhp;
+ int error = 0, wccflag = NFSV3_WCCRATTR, attrflag;
+ int fhsize, gotvp = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
struct vattr vattr;
+ int v3 = NFS_ISV3(dvp);
- error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc);
- if (error) {
+ if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
VOP_ABORTOP(dvp, cnp);
vput(dvp);
return (error);
}
len = cnp->cn_namelen;
- isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
nfsstats.rpccnt[NFSPROC_MKDIR]++;
nfsm_reqhead(dvp, NFSPROC_MKDIR,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
- nfsm_fhtom(dvp);
+ NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
+ nfsm_fhtom(dvp, v3);
nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
- nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
- sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
- sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
- sp->sa_gid = txdr_unsigned(vattr.va_gid);
- if (isnq) {
- quad_t qval = -1;
-
- txdr_hyper(&qval, &sp->sa_nqsize);
- sp->sa_nqflags = 0;
- txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
- txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
+ if (v3) {
+ nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
+ nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
} else {
- sp->sa_nfssize = -1;
- txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
- txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
+ nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
+ sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
+ sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
+ sp->sa_gid = txdr_unsigned(vattr.va_gid);
+ sp->sa_size = -1;
+ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
+ txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
- nfsm_mtofh(dvp, *vpp);
+ if (!error)
+ nfsm_mtofh(dvp, newvp, v3, gotvp);
+ if (v3)
+ nfsm_wcc_data(dvp, wccflag);
nfsm_reqdone;
VTONFS(dvp)->n_flag |= NMODIFIED;
- VTONFS(dvp)->n_attrstamp = 0;
+ if (!wccflag)
+ VTONFS(dvp)->n_attrstamp = 0;
/*
* Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
* if we can succeed in looking up the directory.
- * "firsttry" is necessary since the macros may "goto nfsmout" which
- * is above the if on errors. (Ugh)
*/
- if (error == EEXIST && firsttry) {
- firsttry = 0;
- error = 0;
- nfsstats.rpccnt[NFSPROC_LOOKUP]++;
- *vpp = NULL;
- nfsm_reqhead(dvp, NFSPROC_LOOKUP,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
- nfsm_fhtom(dvp);
- nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
- nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
- nfsm_mtofh(dvp, *vpp);
- if ((*vpp)->v_type != VDIR) {
- vput(*vpp);
- error = EEXIST;
+ if (error == EEXIST || (!error && !gotvp)) {
+ if (newvp) {
+ vrele(newvp);
+ newvp = (struct vnode *)0;
+ }
+ error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
+ cnp->cn_proc, &np);
+ if (!error) {
+ newvp = NFSTOV(np);
+ if (newvp->v_type != VDIR)
+ error = EEXIST;
}
- m_freem(mrep);
}
+ if (error) {
+ if (newvp)
+ vrele(newvp);
+ } else
+ *ap->a_vpp = newvp;
FREE(cnp->cn_pnbuf, M_NAMEI);
- vrele(dvp);
+ vput(dvp);
return (error);
}
@@ -1533,31 +1890,35 @@ nfs_rmdir(ap)
register struct componentname *cnp = ap->a_cnp;
register u_long *tl;
register caddr_t cp;
- register long t2;
- caddr_t bpos, dpos;
- int error = 0;
+ register long t1, t2;
+ caddr_t bpos, dpos, cp2;
+ int error = 0, wccflag = NFSV3_WCCRATTR;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ int v3 = NFS_ISV3(dvp);
if (dvp == vp) {
- vrele(dvp);
+ vput(dvp);
vrele(dvp);
FREE(cnp->cn_pnbuf, M_NAMEI);
return (EINVAL);
}
nfsstats.rpccnt[NFSPROC_RMDIR]++;
nfsm_reqhead(dvp, NFSPROC_RMDIR,
- NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
- nfsm_fhtom(dvp);
+ NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+ nfsm_fhtom(dvp, v3);
nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
+ if (v3)
+ nfsm_wcc_data(dvp, wccflag);
nfsm_reqdone;
FREE(cnp->cn_pnbuf, M_NAMEI);
VTONFS(dvp)->n_flag |= NMODIFIED;
- VTONFS(dvp)->n_attrstamp = 0;
+ if (!wccflag)
+ VTONFS(dvp)->n_attrstamp = 0;
cache_purge(dvp);
cache_purge(vp);
- vrele(vp);
- vrele(dvp);
+ vput(vp);
+ vput(dvp);
/*
* Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
*/
@@ -1568,9 +1929,6 @@ nfs_rmdir(ap)
/*
* nfs readdir call
- * Although cookie is defined as opaque, I translate it to/from net byte
- * order so that it looks more sensible. This appears consistent with the
- * Ultrix implementation of NFS.
*/
int
nfs_readdir(ap)
@@ -1591,10 +1949,10 @@ nfs_readdir(ap)
/*
* First, check for hit on the EOF offset cache
*/
- if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
+ if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
(np->n_flag & NMODIFIED) == 0) {
if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
- if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
+ if (NQNFS_CKCACHABLE(vp, ND_READ)) {
nfsstats.direofcache_hits++;
return (0);
}
@@ -1622,90 +1980,148 @@ nfs_readdir(ap)
*/
int
nfs_readdirrpc(vp, uiop, cred)
- register struct vnode *vp;
- struct uio *uiop;
+ struct vnode *vp;
+ register struct uio *uiop;
struct ucred *cred;
+
{
- register long len;
- register struct dirent *dp = 0;
+ register int len, left;
+ register struct dirent *dp;
register u_long *tl;
register caddr_t cp;
- register long t1;
- long tlen, lastlen = 0;
+ register long t1, t2;
+ register nfsuint64 *cookiep;
caddr_t bpos, dpos, cp2;
- int error = 0;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- struct mbuf *md2;
- caddr_t dpos2;
- int siz;
- int more_dirs = 1;
- u_long off, savoff = 0;
- struct dirent *savdp = 0;
- struct nfsmount *nmp;
- struct nfsnode *np = VTONFS(vp);
- long tresid;
+ nfsuint64 cookie;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ struct nfsnode *dnp = VTONFS(vp);
+ nfsfh_t *fhp;
+ u_quad_t frev, fileno;
+ int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1, i;
+ int cachable, attrflag, fhsize;
+ int v3 = NFS_ISV3(vp);
+
+#ifndef nolint
+ dp = (struct dirent *)0;
+#endif
+#ifndef DIAGNOSTIC
+ if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
+ (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
+ panic("nfs readdirrpc bad uio");
+#endif
- nmp = VFSTONFS(vp->v_mount);
- tresid = uiop->uio_resid;
/*
- * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
- * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
+ * If there is no cookie, assume end of directory.
+ */
+ cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
+ if (cookiep)
+ cookie = *cookiep;
+ else
+ return (0);
+ /*
+ * Loop around doing readdir rpc's of size nm_readdirsize
+ * truncated to a multiple of DIRBLKSIZ.
* The stopping criteria is EOF or buffer full.
*/
- while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
+ while (more_dirs && bigenough) {
nfsstats.rpccnt[NFSPROC_READDIR]++;
- nfsm_reqhead(vp, NFSPROC_READDIR,
- NFSX_FH + 2 * NFSX_UNSIGNED);
- nfsm_fhtom(vp);
- nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
- off = (u_long)uiop->uio_offset;
- *tl++ = txdr_unsigned(off);
- *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
- nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
+ nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
+ NFSX_READDIR(v3));
+ nfsm_fhtom(vp, v3);
+ if (v3) {
+ nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
+ *tl++ = cookie.nfsuquad[0];
+ *tl++ = cookie.nfsuquad[1];
+ *tl++ = dnp->n_cookieverf.nfsuquad[0];
+ *tl++ = dnp->n_cookieverf.nfsuquad[1];
+ } else {
+ nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
+ *tl++ = cookie.nfsuquad[0];
+ }
+ *tl = txdr_unsigned(nmp->nm_readdirsize);
nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
- siz = 0;
+ if (v3) {
+ nfsm_postop_attr(vp, attrflag);
+ if (!error) {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ dnp->n_cookieverf.nfsuquad[0] = *tl++;
+ dnp->n_cookieverf.nfsuquad[1] = *tl;
+ } else {
+ m_freem(mrep);
+ goto nfsmout;
+ }
+ }
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
more_dirs = fxdr_unsigned(int, *tl);
- /* Save the position so that we can do nfsm_mtouio() later */
- dpos2 = dpos;
- md2 = md;
-
/* loop thru the dir entries, doctoring them to 4bsd form */
-#ifdef lint
- dp = (struct dirent *)0;
-#endif /* lint */
- while (more_dirs && siz < uiop->uio_resid) {
- savoff = off; /* Hold onto offset and dp */
- savdp = dp;
- nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
- dp = (struct dirent *)tl;
- dp->d_fileno = fxdr_unsigned(u_long, *tl++);
- len = fxdr_unsigned(int, *tl);
+ while (more_dirs && bigenough) {
+ if (v3) {
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ fxdr_hyper(tl, &fileno);
+ len = fxdr_unsigned(int, *(tl + 2));
+ } else {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ fileno = fxdr_unsigned(u_quad_t, *tl++);
+ len = fxdr_unsigned(int, *tl);
+ }
if (len <= 0 || len > NFS_MAXNAMLEN) {
error = EBADRPC;
m_freem(mrep);
goto nfsmout;
}
- dp->d_namlen = (u_char)len;
- dp->d_type = DT_UNKNOWN;
- nfsm_adv(len); /* Point past name */
tlen = nfsm_rndup(len);
- /*
- * This should not be necessary, but some servers have
- * broken XDR such that these bytes are not null filled.
- */
- if (tlen != len) {
- *dpos = '\0'; /* Null-terminate */
- nfsm_adv(tlen - len);
- len = tlen;
+ if (tlen == len)
+ tlen += 4; /* To ensure null termination */
+ left = DIRBLKSIZ - blksiz;
+ if ((tlen + DIRHDSIZ) > left) {
+ dp->d_reclen += left;
+ uiop->uio_iov->iov_base += left;
+ uiop->uio_iov->iov_len -= left;
+ uiop->uio_offset += left;
+ uiop->uio_resid -= left;
+ blksiz = 0;
}
- nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
- off = fxdr_unsigned(u_long, *tl);
- *tl++ = 0; /* Ensures null termination of name */
+ if ((tlen + DIRHDSIZ) > uiop->uio_resid)
+ bigenough = 0;
+ if (bigenough) {
+ dp = (struct dirent *)uiop->uio_iov->iov_base;
+ dp->d_fileno = (int)fileno;
+ dp->d_namlen = len;
+ dp->d_reclen = tlen + DIRHDSIZ;
+ dp->d_type = DT_UNKNOWN;
+ blksiz += dp->d_reclen;
+ if (blksiz == DIRBLKSIZ)
+ blksiz = 0;
+ uiop->uio_offset += DIRHDSIZ;
+ uiop->uio_resid -= DIRHDSIZ;
+ uiop->uio_iov->iov_base += DIRHDSIZ;
+ uiop->uio_iov->iov_len -= DIRHDSIZ;
+ nfsm_mtouio(uiop, len);
+ cp = uiop->uio_iov->iov_base;
+ tlen -= len;
+ *cp = '\0'; /* null terminate */
+ uiop->uio_iov->iov_base += tlen;
+ uiop->uio_iov->iov_len -= tlen;
+ uiop->uio_offset += tlen;
+ uiop->uio_resid -= tlen;
+ } else
+ nfsm_adv(nfsm_rndup(len));
+ if (v3) {
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ } else {
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
+ }
+ if (bigenough) {
+ cookie.nfsuquad[0] = *tl++;
+ if (v3)
+ cookie.nfsuquad[1] = *tl++;
+ } else if (v3)
+ tl += 2;
+ else
+ tl++;
more_dirs = fxdr_unsigned(int, *tl);
- dp->d_reclen = len + 4 * NFSX_UNSIGNED;
- siz += dp->d_reclen;
}
/*
* If at end of rpc data, get the eof boolean
@@ -1713,189 +2129,224 @@ nfs_readdirrpc(vp, uiop, cred)
if (!more_dirs) {
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
more_dirs = (fxdr_unsigned(int, *tl) == 0);
-
- /*
- * If at EOF, cache directory offset
- */
- if (!more_dirs)
- np->n_direofoffset = off;
- }
- /*
- * If there is too much to fit in the data buffer, use savoff and
- * savdp to trim off the last record.
- * --> we are not at eof
- */
- if (siz > uiop->uio_resid) {
- off = savoff;
- siz -= dp->d_reclen;
- dp = savdp;
- more_dirs = 0; /* Paranoia */
}
- if (siz > 0) {
- lastlen = dp->d_reclen;
- md = md2;
- dpos = dpos2;
- nfsm_mtouio(uiop, siz);
- uiop->uio_offset = (off_t)off;
- } else
- more_dirs = 0; /* Ugh, never happens, but in case.. */
m_freem(mrep);
}
/*
- * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
+ * Fill last record, iff any, out to a multiple of DIRBLKSIZ
* by increasing d_reclen for the last record.
*/
- if (uiop->uio_resid < tresid) {
- len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
- if (len > 0) {
- dp = (struct dirent *)
- (uiop->uio_iov->iov_base - lastlen);
- dp->d_reclen += len;
- uiop->uio_iov->iov_base += len;
- uiop->uio_iov->iov_len -= len;
- uiop->uio_resid -= len;
- }
+ if (blksiz > 0) {
+ left = DIRBLKSIZ - blksiz;
+ dp->d_reclen += left;
+ uiop->uio_iov->iov_base += left;
+ uiop->uio_iov->iov_len -= left;
+ uiop->uio_offset += left;
+ uiop->uio_resid -= left;
+ }
+
+ /*
+ * We are now either at the end of the directory or have filled the
+ * block.
+ */
+ if (bigenough)
+ dnp->n_direofoffset = uiop->uio_offset;
+ else {
+ if (uiop->uio_resid > 0)
+ printf("EEK! readdirrpc resid > 0\n");
+ cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
+ *cookiep = cookie;
}
nfsmout:
return (error);
}
/*
- * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
+ * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
*/
int
-nfs_readdirlookrpc(vp, uiop, cred)
+nfs_readdirplusrpc(vp, uiop, cred)
struct vnode *vp;
register struct uio *uiop;
struct ucred *cred;
{
- register int len;
- register struct dirent *dp = 0;
+ register int len, left;
+ register struct dirent *dp;
register u_long *tl;
register caddr_t cp;
- register long t1;
- caddr_t bpos, dpos, cp2;
- struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+ register long t1, t2;
+ register struct vnode *newvp;
+ register nfsuint64 *cookiep;
+ caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
+ struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
struct nameidata nami, *ndp = &nami;
struct componentname *cnp = &ndp->ni_cnd;
- u_long off, endoff = 0, fileno;
- time_t reqtime, ltime = 0;
- struct nfsmount *nmp;
- struct nfsnode *np;
- struct vnode *newvp;
- nfsv2fh_t *fhp;
- u_quad_t frev;
- int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
- int cachable = 0;
-
- if (uiop->uio_iovcnt != 1)
- panic("nfs rdirlook");
- nmp = VFSTONFS(vp->v_mount);
- tresid = uiop->uio_resid;
+ nfsuint64 cookie;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ struct nfsnode *dnp = VTONFS(vp), *np;
+ nfsfh_t *fhp;
+ u_quad_t frev, fileno;
+ int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
+ int cachable, attrflag, fhsize;
+
+#ifndef nolint
+ dp = (struct dirent *)0;
+#endif
+#ifndef DIAGNOSTIC
+ if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
+ (uiop->uio_resid & (DIRBLKSIZ - 1)))
+ panic("nfs readdirplusrpc bad uio");
+#endif
ndp->ni_dvp = vp;
newvp = NULLVP;
+
/*
- * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
- * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
+ * If there is no cookie, assume end of directory.
+ */
+ cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
+ if (cookiep)
+ cookie = *cookiep;
+ else
+ return (0);
+ /*
+ * Loop around doing readdir rpc's of size nm_readdirsize
+ * truncated to a multiple of DIRBLKSIZ.
* The stopping criteria is EOF or buffer full.
*/
- while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
- nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
- nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
- NFSX_FH + 3 * NFSX_UNSIGNED);
- nfsm_fhtom(vp);
- nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
- off = (u_long)uiop->uio_offset;
- *tl++ = txdr_unsigned(off);
- *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
- nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
- if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
- *tl = txdr_unsigned(nmp->nm_leaseterm);
- else
- *tl = 0;
- reqtime = time.tv_sec;
- nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
- nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ while (more_dirs && bigenough) {
+ nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
+ nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
+ NFSX_FH(1) + 6 * NFSX_UNSIGNED);
+ nfsm_fhtom(vp, 1);
+ nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
+ *tl++ = cookie.nfsuquad[0];
+ *tl++ = cookie.nfsuquad[1];
+ *tl++ = dnp->n_cookieverf.nfsuquad[0];
+ *tl++ = dnp->n_cookieverf.nfsuquad[1];
+ *tl++ = txdr_unsigned(nmp->nm_readdirsize);
+ *tl = txdr_unsigned(nmp->nm_rsize);
+ nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
+ nfsm_postop_attr(vp, attrflag);
+ if (error) {
+ m_freem(mrep);
+ goto nfsmout;
+ }
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ dnp->n_cookieverf.nfsuquad[0] = *tl++;
+ dnp->n_cookieverf.nfsuquad[1] = *tl++;
more_dirs = fxdr_unsigned(int, *tl);
/* loop thru the dir entries, doctoring them to 4bsd form */
- bigenough = 1;
while (more_dirs && bigenough) {
- doit = 1;
- nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
- if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
- cachable = fxdr_unsigned(int, *tl++);
- ltime = reqtime + fxdr_unsigned(int, *tl++);
- fxdr_hyper(tl, &frev);
- }
- nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
- if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
- VREF(vp);
- newvp = vp;
- np = VTONFS(vp);
- } else {
- error = nfs_nget(vp->v_mount, fhp, &np);
- if (error)
- doit = 0;
- newvp = NFSTOV(np);
- }
- error = nfs_loadattrcache(&newvp, &md, &dpos,
- (struct vattr *)0);
- if (error)
- doit = 0;
- nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
- fileno = fxdr_unsigned(u_long, *tl++);
- len = fxdr_unsigned(int, *tl);
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ fxdr_hyper(tl, &fileno);
+ len = fxdr_unsigned(int, *(tl + 2));
if (len <= 0 || len > NFS_MAXNAMLEN) {
error = EBADRPC;
m_freem(mrep);
goto nfsmout;
}
- tlen = (len + 4) & ~0x3;
+ tlen = nfsm_rndup(len);
+ if (tlen == len)
+ tlen += 4; /* To ensure null termination*/
+ left = DIRBLKSIZ - blksiz;
+ if ((tlen + DIRHDSIZ) > left) {
+ dp->d_reclen += left;
+ uiop->uio_iov->iov_base += left;
+ uiop->uio_iov->iov_len -= left;
+ uiop->uio_offset += left;
+ uiop->uio_resid -= left;
+ blksiz = 0;
+ }
if ((tlen + DIRHDSIZ) > uiop->uio_resid)
bigenough = 0;
- if (bigenough && doit) {
+ if (bigenough) {
dp = (struct dirent *)uiop->uio_iov->iov_base;
- dp->d_fileno = fileno;
+ dp->d_fileno = (int)fileno;
dp->d_namlen = len;
dp->d_reclen = tlen + DIRHDSIZ;
- dp->d_type =
- IFTODT(VTTOIF(np->n_vattr.va_type));
+ dp->d_type = DT_UNKNOWN;
+ blksiz += dp->d_reclen;
+ if (blksiz == DIRBLKSIZ)
+ blksiz = 0;
+ uiop->uio_offset += DIRHDSIZ;
uiop->uio_resid -= DIRHDSIZ;
uiop->uio_iov->iov_base += DIRHDSIZ;
uiop->uio_iov->iov_len -= DIRHDSIZ;
cnp->cn_nameptr = uiop->uio_iov->iov_base;
cnp->cn_namelen = len;
- ndp->ni_vp = newvp;
nfsm_mtouio(uiop, len);
cp = uiop->uio_iov->iov_base;
tlen -= len;
- for (i = 0; i < tlen; i++)
- *cp++ = '\0';
+ *cp = '\0';
uiop->uio_iov->iov_base += tlen;
uiop->uio_iov->iov_len -= tlen;
+ uiop->uio_offset += tlen;
uiop->uio_resid -= tlen;
+ } else
+ nfsm_adv(nfsm_rndup(len));
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ if (bigenough) {
+ cookie.nfsuquad[0] = *tl++;
+ cookie.nfsuquad[1] = *tl++;
+ } else
+ tl += 2;
+
+ /*
+ * Since the attributes are before the file handle
+ * (sigh), we must skip over the attributes and then
+ * come back and get them.
+ */
+ attrflag = fxdr_unsigned(int, *tl);
+ if (attrflag) {
+ dpossav1 = dpos;
+ mdsav1 = md;
+ nfsm_adv(NFSX_V3FATTR);
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ doit = fxdr_unsigned(int, *tl);
+ if (doit) {
+ nfsm_getfh(fhp, fhsize, 1);
+ if (NFS_CMPFH(dnp, fhp, fhsize)) {
+ VREF(vp);
+ newvp = vp;
+ np = dnp;
+ } else {
+ if (error = nfs_nget(vp->v_mount, fhp,
+ fhsize, &np))
+ doit = 0;
+ else
+ newvp = NFSTOV(np);
+ }
+ }
+ if (doit) {
+ dpossav2 = dpos;
+ dpos = dpossav1;
+ mdsav2 = md;
+ md = mdsav1;
+ nfsm_loadattr(newvp, (struct vattr *)0);
+ dpos = dpossav2;
+ md = mdsav2;
+ dp->d_type =
+ IFTODT(VTTOIF(np->n_vattr.va_type));
+ ndp->ni_vp = newvp;
cnp->cn_hash = 0;
- for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
- cnp->cn_hash += (unsigned char)*cp * i;
- if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
- ltime > time.tv_sec)
- nqnfs_clientlease(nmp, np, NQL_READ,
- cachable, ltime, frev);
+ for (cp = cnp->cn_nameptr, i = 1; i <= len;
+ i++, cp++)
+ cnp->cn_hash += (unsigned char)*cp * i;
if (cnp->cn_namelen <= NCHNAMLEN)
cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
+ }
} else {
- nfsm_adv(nfsm_rndup(len));
+ /* Just skip over the file handle */
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
+ i = fxdr_unsigned(int, *tl);
+ nfsm_adv(nfsm_rndup(i));
}
if (newvp != NULLVP) {
- vrele(newvp);
- newvp = NULLVP;
+ vrele(newvp);
+ newvp = NULLVP;
}
- nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
- if (bigenough)
- endoff = off = fxdr_unsigned(u_long, *tl++);
- else
- endoff = fxdr_unsigned(u_long, *tl++);
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
more_dirs = fxdr_unsigned(int, *tl);
}
/*
@@ -1904,35 +2355,42 @@ nfs_readdirlookrpc(vp, uiop, cred)
if (!more_dirs) {
nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
more_dirs = (fxdr_unsigned(int, *tl) == 0);
-
- /*
- * If at EOF, cache directory offset
- */
- if (!more_dirs)
- VTONFS(vp)->n_direofoffset = endoff;
}
- if (uiop->uio_resid < tresid)
- uiop->uio_offset = (off_t)off;
- else
- more_dirs = 0;
m_freem(mrep);
}
/*
* Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
* by increasing d_reclen for the last record.
*/
- if (uiop->uio_resid < tresid) {
- len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
- if (len > 0) {
- dp->d_reclen += len;
- uiop->uio_iov->iov_base += len;
- uiop->uio_iov->iov_len -= len;
- uiop->uio_resid -= len;
- }
+ if (blksiz > 0) {
+ left = DIRBLKSIZ - blksiz;
+ dp->d_reclen += left;
+ uiop->uio_iov->iov_base += left;
+ uiop->uio_iov->iov_len -= left;
+ uiop->uio_offset += left;
+ uiop->uio_resid -= left;
+ }
+
+ /*
+ * We are now either at the end of the directory or have filled the
+ * block.
+ */
+ if (bigenough)
+ dnp->n_direofoffset = uiop->uio_offset;
+ else {
+ if (uiop->uio_resid > 0)
+ printf("EEK! readdirplusrpc resid > 0\n");
+ cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
+ *cookiep = cookie;
}
nfsmout:
- if (newvp != NULLVP)
- vrele(newvp);
+ if (newvp != NULLVP) {
+ if (newvp == vp)
+ vrele(newvp);
+ else
+ vput(newvp);
+ newvp = NULLVP;
+ }
return (error);
}
static char hextoasc[] = "0123456789abcdef";
@@ -1950,19 +2408,19 @@ nfs_sillyrename(dvp, vp, cnp)
struct vnode *dvp, *vp;
struct componentname *cnp;
{
- register struct nfsnode *np;
register struct sillyrename *sp;
+ struct nfsnode *np;
int error;
short pid;
cache_purge(dvp);
np = VTONFS(vp);
-#ifdef SILLYSEPARATE
+#ifndef DIAGNOSTIC
+ if (vp->v_type == VDIR)
+ panic("nfs: sillyrename dir");
+#endif
MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
M_NFSREQ, M_WAITOK);
-#else
- sp = &np->n_silly;
-#endif
sp->s_cred = crdup(cnp->cn_cred);
sp->s_dvp = dvp;
VREF(dvp);
@@ -1977,65 +2435,149 @@ nfs_sillyrename(dvp, vp, cnp)
sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
/* Try lookitups until we get one that isn't there */
- while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
+ while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
+ cnp->cn_proc, (struct nfsnode **)0) == 0) {
sp->s_name[4]++;
if (sp->s_name[4] > 'z') {
error = EINVAL;
goto bad;
}
}
- error = nfs_renameit(dvp, cnp, sp);
- if (error)
+ if (error = nfs_renameit(dvp, cnp, sp))
goto bad;
- nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
+ error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
+ cnp->cn_proc, &np);
np->n_sillyrename = sp;
return (0);
bad:
vrele(sp->s_dvp);
crfree(sp->s_cred);
-#ifdef SILLYSEPARATE
free((caddr_t)sp, M_NFSREQ);
-#endif
return (error);
}
/*
- * Look up a file name for silly rename stuff.
- * Just like nfs_lookup() except that it doesn't load returned values
- * into the nfsnode table.
- * If fhp != NULL it copies the returned file handle out
+ * Look up a file name and optionally either update the file handle or
+ * allocate an nfsnode, depending on the value of npp.
+ * npp == NULL --> just do the lookup
+ * *npp == NULL --> allocate a new nfsnode and make sure attributes are
+ * handled too
+ * *npp != NULL --> update the file handle in the vnode
*/
int
-nfs_lookitup(sp, fhp, procp)
- register struct sillyrename *sp;
- nfsv2fh_t *fhp;
+nfs_lookitup(dvp, name, len, cred, procp, npp)
+ register struct vnode *dvp;
+ char *name;
+ int len;
+ struct ucred *cred;
struct proc *procp;
+ struct nfsnode **npp;
{
- register struct vnode *vp = sp->s_dvp;
register u_long *tl;
register caddr_t cp;
register long t1, t2;
+ struct vnode *newvp = (struct vnode *)0;
+ struct nfsnode *np, *dnp = VTONFS(dvp);
caddr_t bpos, dpos, cp2;
- int error = 0, isnq;
+ int error = 0, fhlen, attrflag;
struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- long len;
+ nfsfh_t *nfhp;
+ int v3 = NFS_ISV3(dvp);
- isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
nfsstats.rpccnt[NFSPROC_LOOKUP]++;
- len = sp->s_namlen;
- nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
- if (isnq) {
- nfsm_build(tl, u_long *, NFSX_UNSIGNED);
- *tl = 0;
+ nfsm_reqhead(dvp, NFSPROC_LOOKUP,
+ NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+ nfsm_fhtom(dvp, v3);
+ nfsm_strtom(name, len, NFS_MAXNAMLEN);
+ nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
+ if (npp && !error) {
+ nfsm_getfh(nfhp, fhlen, v3);
+ if (*npp) {
+ np = *npp;
+ if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
+ free((caddr_t)np->n_fhp, M_NFSBIGFH);
+ np->n_fhp = &np->n_fh;
+ } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
+ np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
+ bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
+ np->n_fhsize = fhlen;
+ newvp = NFSTOV(np);
+ } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
+ VREF(dvp);
+ newvp = dvp;
+ } else {
+ error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
+ if (error) {
+ m_freem(mrep);
+ return (error);
+ }
+ newvp = NFSTOV(np);
+ }
+ if (v3) {
+ nfsm_postop_attr(newvp, attrflag);
+ if (!attrflag && *npp == NULL) {
+ m_freem(mrep);
+ if (newvp == dvp)
+ vrele(newvp);
+ else
+ vput(newvp);
+ return (ENOENT);
+ }
+ } else
+ nfsm_loadattr(newvp, (struct vattr *)0);
}
- nfsm_fhtom(vp);
- nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
- nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
- if (fhp != NULL) {
- if (isnq)
- nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
- nfsm_dissect(cp, caddr_t, NFSX_FH);
- bcopy(cp, (caddr_t)fhp, NFSX_FH);
+ nfsm_reqdone;
+ if (npp && *npp == NULL) {
+ if (error) {
+ if (newvp)
+ if (newvp == dvp)
+ vrele(newvp);
+ else
+ vput(newvp);
+ } else
+ *npp = np;
+ }
+ return (error);
+}
+
+/*
+ * Nfs Version 3 commit rpc
+ */
+int
+nfs_commit(vp, offset, cnt, cred, procp)
+ register struct vnode *vp;
+ u_quad_t offset;
+ int cnt;
+ struct ucred *cred;
+ struct proc *procp;
+{
+ register caddr_t cp;
+ register u_long *tl;
+ register int t1, t2;
+ register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ caddr_t bpos, dpos, cp2;
+ int error = 0, wccflag = NFSV3_WCCRATTR;
+ struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+
+ if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
+ return (0);
+ nfsstats.rpccnt[NFSPROC_COMMIT]++;
+ nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
+ nfsm_fhtom(vp, 1);
+ nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
+ txdr_hyper(&offset, tl);
+ tl += 2;
+ *tl = txdr_unsigned(cnt);
+ nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
+ nfsm_wcc_data(vp, wccflag);
+ if (!error) {
+ nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
+ if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
+ NFSX_V3WRITEVERF)) {
+ bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
+ NFSX_V3WRITEVERF);
+ error = NFSERR_STALEWRITEVERF;
+ }
}
nfsm_reqdone;
return (error);
@@ -2044,9 +2586,7 @@ nfs_lookitup(sp, fhp, procp)
/*
* Kludge City..
* - make nfs_bmap() essentially a no-op that does no translation
- * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
- * after mapping the physical addresses into Kernel Virtual space in the
- * nfsiobuf area.
+ * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
* (Maybe I could use the process's page mapping, but I was concerned that
* Kernel Write might not be enabled and also figured copyout() would do
* a lot more work than bcopy() and also it currently happens in the
@@ -2088,8 +2628,8 @@ nfs_strategy(ap)
struct proc *p;
int error = 0;
- if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC))
- panic("nfs physio/async");
+ if (bp->b_flags & B_PHYS)
+ panic("nfs physio");
if (bp->b_flags & B_ASYNC)
p = (struct proc *)0;
else
@@ -2129,9 +2669,7 @@ nfs_mmap(ap)
}
/*
- * Flush all the blocks associated with a vnode.
- * Walk through the buffer pool and push any dirty pages
- * associated with the vnode.
+ * fsync vnode op. Just call nfs_flush() with commit == 1.
*/
/* ARGSUSED */
int
@@ -2144,29 +2682,124 @@ nfs_fsync(ap)
struct proc * a_p;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
+
+ return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
+}
+
+/*
+ * Flush all the blocks associated with a vnode.
+ * Walk through the buffer pool and push any dirty pages
+ * associated with the vnode.
+ */
+int
+nfs_flush(vp, cred, waitfor, p, commit)
+ register struct vnode *vp;
+ struct ucred *cred;
+ int waitfor;
+ struct proc *p;
+ int commit;
+{
register struct nfsnode *np = VTONFS(vp);
register struct buf *bp;
+ register int i;
struct buf *nbp;
- struct nfsmount *nmp;
- int s, error = 0, slptimeo = 0, slpflag = 0;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
+ int passone = 1;
+ u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
+#ifndef NFS_COMMITBVECSIZ
+#define NFS_COMMITBVECSIZ 20
+#endif
+ struct buf *bvec[NFS_COMMITBVECSIZ];
- nmp = VFSTONFS(vp->v_mount);
if (nmp->nm_flag & NFSMNT_INT)
slpflag = PCATCH;
+ if (!commit)
+ passone = 0;
+ /*
+ * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
+ * server, but nas not been committed to stable storage on the server
+ * yet. On the first pass, the byte range is worked out and the commit
+ * rpc is done. On the second pass, nfs_writebp() is called to do the
+ * job.
+ */
+again:
+ bvecpos = 0;
+ if (NFS_ISV3(vp) && commit) {
+ s = splbio();
+ for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
+ nbp = bp->b_vnbufs.le_next;
+ if (bvecpos >= NFS_COMMITBVECSIZ)
+ break;
+ if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
+ != (B_DELWRI | B_NEEDCOMMIT))
+ continue;
+ bremfree(bp);
+ bp->b_flags |= (B_BUSY | B_WRITEINPROG);
+ vfs_busy_pages(bp, 1);
+ /*
+ * A list of these buffers is kept so that the
+ * second loop knows which buffers have actually
+ * been committed. This is necessary, since there
+ * may be a race between the commit rpc and new
+ * uncommitted writes on the file.
+ */
+ bvec[bvecpos++] = bp;
+ toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
+ bp->b_dirtyoff;
+ if (toff < off)
+ off = toff;
+ toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
+ if (toff > endoff)
+ endoff = toff;
+ }
+ splx(s);
+ }
+ if (bvecpos > 0) {
+ /*
+ * Commit data on the server, as required.
+ */
+ retv = nfs_commit(vp, off, (int)(endoff - off), cred, p);
+ if (retv == NFSERR_STALEWRITEVERF)
+ nfs_clearcommit(vp->v_mount);
+ /*
+ * Now, either mark the blocks I/O done or mark the
+ * blocks dirty, depending on whether the commit
+ * succeeded.
+ */
+ for (i = 0; i < bvecpos; i++) {
+ bp = bvec[i];
+ bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
+ if (retv) {
+ brelse(bp);
+ vfs_unbusy_pages(bp);
+ } else {
+ vp->v_numoutput++;
+ bp->b_flags |= B_ASYNC;
+ bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
+ bp->b_dirtyoff = bp->b_dirtyend = 0;
+ reassignbuf(bp, vp);
+ biodone(bp);
+ }
+ }
+ }
+
+ /*
+ * Start/do any write(s) that are required.
+ */
loop:
s = splbio();
for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
nbp = bp->b_vnbufs.le_next;
if (bp->b_flags & B_BUSY) {
- if (ap->a_waitfor != MNT_WAIT)
+ if (waitfor != MNT_WAIT || passone)
continue;
bp->b_flags |= B_WANTED;
error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
"nfsfsync", slptimeo);
splx(s);
if (error) {
- if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
+ if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
return (EINTR);
if (slpflag == PCATCH) {
slpflag = 0;
@@ -2177,21 +2810,29 @@ loop:
}
if ((bp->b_flags & B_DELWRI) == 0)
panic("nfs_fsync: not dirty");
+ if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
+ continue;
bremfree(bp);
- bp->b_flags |= B_BUSY;
+ if (passone || !commit)
+ bp->b_flags |= (B_BUSY|B_ASYNC);
+ else
+ bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
splx(s);
- bp->b_flags |= B_ASYNC;
VOP_BWRITE(bp);
goto loop;
}
splx(s);
- if (ap->a_waitfor == MNT_WAIT) {
+ if (passone) {
+ passone = 0;
+ goto again;
+ }
+ if (waitfor == MNT_WAIT) {
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
error = tsleep((caddr_t)&vp->v_numoutput,
slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
if (error) {
- if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
+ if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
return (EINTR);
if (slpflag == PCATCH) {
slpflag = 0;
@@ -2199,7 +2840,7 @@ loop:
}
}
}
- if (vp->v_dirtyblkhd.lh_first) {
+ if (vp->v_dirtyblkhd.lh_first && commit) {
goto loop;
}
}
@@ -2207,14 +2848,15 @@ loop:
error = np->n_error;
np->n_flag &= ~NWRITEERR;
}
+ np->n_flag &= ~NMODIFIED;
return (error);
}
/*
* Return POSIX pathconf information applicable to nfs.
*
- * Currently the NFS protocol does not support getting such
- * information from the remote server.
+ * The NFS V2 protocol doesn't support this, so just return EINVAL
+ * for V2.
*/
/* ARGSUSED */
int
@@ -2243,6 +2885,7 @@ nfs_advlock(ap)
int a_flags;
} */ *ap;
{
+#ifdef __FreeBSD__
register struct nfsnode *np = VTONFS(ap->a_vp);
/*
@@ -2251,6 +2894,9 @@ nfs_advlock(ap)
* that this is a local lock.
*/
return (lf_advlock(ap, &(np->n_lockf), np->n_size));
+#else
+ return (EOPNOTSUPP);
+#endif
}
/*
@@ -2363,6 +3009,81 @@ nfs_update(ap)
}
/*
+ * Just call nfs_writebp() with the force argument set to 1.
+ */
+int
+nfs_bwrite(ap)
+ struct vop_bwrite_args /* {
+ struct vnode *a_bp;
+ } */ *ap;
+{
+
+ return (nfs_writebp(ap->a_bp, 1));
+}
+
+/*
+ * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
+ * the force flag is one and it also handles the B_NEEDCOMMIT flag.
+ */
+int
+nfs_writebp(bp, force)
+ register struct buf *bp;
+ int force;
+{
+ register int oldflags = bp->b_flags, retv = 1;
+ off_t off;
+
+ if(!(bp->b_flags & B_BUSY))
+ panic("bwrite: buffer is not busy???");
+
+ bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
+
+ if ((oldflags & (B_ASYNC|B_DELWRI)) == (B_ASYNC|B_DELWRI)) {
+ reassignbuf(bp, bp->b_vp);
+ }
+
+ bp->b_vp->v_numoutput++;
+ curproc->p_stats->p_ru.ru_oublock++;
+
+ /*
+ * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
+ * an actual write will have to be scheduled via. VOP_STRATEGY().
+ * If B_WRITEINPROG is already set, then push it with a write anyhow.
+ */
+ if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) {
+ off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
+ bp->b_flags |= B_WRITEINPROG;
+ retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
+ bp->b_wcred, bp->b_proc);
+ bp->b_flags &= ~B_WRITEINPROG;
+ if (!retv) {
+ bp->b_dirtyoff = bp->b_dirtyend = 0;
+ bp->b_flags &= ~B_NEEDCOMMIT;
+ biodone(bp);
+ } else if (retv == NFSERR_STALEWRITEVERF)
+ nfs_clearcommit(bp->b_vp->v_mount);
+ }
+ if (retv) {
+ if (force)
+ bp->b_flags |= B_WRITEINPROG;
+ vfs_busy_pages(bp, 1);
+ VOP_STRATEGY(bp);
+ }
+
+ if( (oldflags & B_ASYNC) == 0) {
+ int rtval = biowait(bp);
+
+ if (oldflags & B_DELWRI) {
+ reassignbuf(bp, bp->b_vp);
+ }
+ brelse(bp);
+ return (rtval);
+ }
+
+ return (0);
+}
+
+/*
* nfs special file access vnode op.
* Essentially just get vattr and then imitate iaccess() since the device is
* local to the client.
@@ -2409,7 +3130,8 @@ nfsspec_access(ap)
found:
;
}
- return ((vap->va_mode & mode) == mode ? 0 : EACCES);
+ error = (vap->va_mode & mode) == mode ? 0 : EACCES;
+ return (error);
}
/*
@@ -2430,7 +3152,8 @@ nfsspec_read(ap)
* Set access flag.
*/
np->n_flag |= NACC;
- np->n_atim = time;
+ np->n_atim.ts_sec = time.tv_sec;
+ np->n_atim.ts_nsec = time.tv_usec * 1000;
return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
}
@@ -2452,7 +3175,8 @@ nfsspec_write(ap)
* Set update flag.
*/
np->n_flag |= NUPD;
- np->n_mtim = time;
+ np->n_mtim.ts_sec = time.tv_sec;
+ np->n_mtim.ts_nsec = time.tv_usec * 1000;
return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
}
@@ -2479,16 +3203,10 @@ nfsspec_close(ap)
if (vp->v_usecount == 1 &&
(vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
VATTR_NULL(&vattr);
- if (np->n_flag & NACC) {
- vattr.va_atime.ts_sec = np->n_atim.tv_sec;
- vattr.va_atime.ts_nsec =
- np->n_atim.tv_usec * 1000;
- }
- if (np->n_flag & NUPD) {
- vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
- vattr.va_mtime.ts_nsec =
- np->n_mtim.tv_usec * 1000;
- }
+ if (np->n_flag & NACC)
+ vattr.va_atime = np->n_atim;
+ if (np->n_flag & NUPD)
+ vattr.va_mtime = np->n_mtim;
(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
}
}
@@ -2513,7 +3231,8 @@ nfsfifo_read(ap)
* Set access flag.
*/
np->n_flag |= NACC;
- np->n_atim = time;
+ np->n_atim.ts_sec = time.tv_sec;
+ np->n_atim.ts_nsec = time.tv_usec * 1000;
return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
}
@@ -2535,7 +3254,8 @@ nfsfifo_write(ap)
* Set update flag.
*/
np->n_flag |= NUPD;
- np->n_mtim = time;
+ np->n_mtim.ts_sec = time.tv_sec;
+ np->n_mtim.ts_nsec = time.tv_usec * 1000;
return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
}
@@ -2558,24 +3278,22 @@ nfsfifo_close(ap)
struct vattr vattr;
if (np->n_flag & (NACC | NUPD)) {
- if (np->n_flag & NACC)
- np->n_atim = time;
- if (np->n_flag & NUPD)
- np->n_mtim = time;
+ if (np->n_flag & NACC) {
+ np->n_atim.ts_sec = time.tv_sec;
+ np->n_atim.ts_nsec = time.tv_usec * 1000;
+ }
+ if (np->n_flag & NUPD) {
+ np->n_mtim.ts_sec = time.tv_sec;
+ np->n_mtim.ts_nsec = time.tv_usec * 1000;
+ }
np->n_flag |= NCHG;
if (vp->v_usecount == 1 &&
(vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
VATTR_NULL(&vattr);
- if (np->n_flag & NACC) {
- vattr.va_atime.ts_sec = np->n_atim.tv_sec;
- vattr.va_atime.ts_nsec =
- np->n_atim.tv_usec * 1000;
- }
- if (np->n_flag & NUPD) {
- vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
- vattr.va_mtime.ts_nsec =
- np->n_mtim.tv_usec * 1000;
- }
+ if (np->n_flag & NACC)
+ vattr.va_atime = np->n_atim;
+ if (np->n_flag & NUPD)
+ vattr.va_mtime = np->n_mtim;
(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
}
}
diff --git a/sys/nfs/nfsdiskless.h b/sys/nfs/nfsdiskless.h
index 5df85e0f6592..f7371dcc0d3c 100644
--- a/sys/nfs/nfsdiskless.h
+++ b/sys/nfs/nfsdiskless.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93
- * $Id: nfsdiskless.h,v 1.3 1994/08/05 09:28:49 davidg Exp $
+ * $Id: nfsdiskless.h,v 1.4 1994/08/21 06:50:09 paul Exp $
*/
#ifndef _NFS_NFSDISKLESS_H_
@@ -52,17 +52,45 @@
* NB: All fields are stored in net byte order to avoid hassles with
* client/server byte ordering differences.
*/
+
+/*
+ * I have defined a new structure that can handle an NFS Version 3 file handle
+ * but the kernel still expects the old Version 2 one to be provided. The
+ * changes required in nfs_vfsops.c for using the new are documented there in
+ * comments. (I felt that breaking network booting code by changing this
+ * structure would not be prudent at this time, since almost all servers are
+ * still Version 2 anyhow.)
+ */
+struct nfsv3_diskless {
+ struct ifaliasreq myif; /* Default interface */
+ struct sockaddr_in mygateway; /* Default gateway */
+ struct nfs_args swap_args; /* Mount args for swap file */
+ int swap_fhsize; /* Size of file handle */
+ u_char swap_fh[NFSX_V3FHMAX]; /* Swap file's file handle */
+ struct sockaddr_in swap_saddr; /* Address of swap server */
+ char swap_hostnam[MNAMELEN]; /* Host name for mount pt */
+ int swap_nblks; /* Size of server swap file */
+ struct ucred swap_ucred; /* Swap credentials */
+ struct nfs_args root_args; /* Mount args for root fs */
+ int root_fhsize; /* Size of root file handle */
+ u_char root_fh[NFSX_V3FHMAX]; /* File handle of root dir */
+ struct sockaddr_in root_saddr; /* Address of root server */
+ char root_hostnam[MNAMELEN]; /* Host name for mount pt */
+ long root_time; /* Timestamp of root fs */
+ char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */
+};
+
struct nfs_diskless {
struct ifaliasreq myif; /* Default interface */
struct sockaddr_in mygateway; /* Default gateway */
struct nfs_args swap_args; /* Mount args for swap file */
- u_char swap_fh[NFS_FHSIZE]; /* Swap file's file handle */
+ u_char swap_fh[NFSX_V2FH]; /* Swap file's file handle */
struct sockaddr_in swap_saddr; /* Address of swap server */
char swap_hostnam[MNAMELEN]; /* Host name for mount pt */
int swap_nblks; /* Size of server swap file */
struct ucred swap_ucred; /* Swap credentials */
struct nfs_args root_args; /* Mount args for root fs */
- u_char root_fh[NFS_FHSIZE]; /* File handle of root dir */
+ u_char root_fh[NFSX_V2FH]; /* File handle of root dir */
struct sockaddr_in root_saddr; /* Address of root server */
char root_hostnam[MNAMELEN]; /* Host name for mount pt */
long root_time; /* Timestamp of root fs */
diff --git a/sys/nfs/nfsm_subs.h b/sys/nfs/nfsm_subs.h
index 030a985b40d1..9e89c57b1c08 100644
--- a/sys/nfs/nfsm_subs.h
+++ b/sys/nfs/nfsm_subs.h
@@ -34,12 +34,13 @@
* SUCH DAMAGE.
*
* @(#)nfsm_subs.h 8.1 (Berkeley) 6/16/93
- * $Id: nfsm_subs.h,v 1.5 1994/10/17 17:47:42 phk Exp $
+ * $Id: nfsm_subs.h,v 1.6 1995/05/30 08:12:51 rgrimes Exp $
*/
#ifndef _NFS_NFSM_SUBS_H_
#define _NFS_NFSM_SUBS_H_
+
/*
* These macros do strange and peculiar things to mbuf chains for
* the assistance of the nfs code. To attempt to use them for any
@@ -90,49 +91,153 @@ extern struct mbuf *nfsm_reqh();
mb->m_len += (s); \
bpos += (s); }
-#define nfsm_dissect(a,c,s) \
+#define nfsm_dissect(a, c, s) \
{ t1 = mtod(md, caddr_t)+md->m_len-dpos; \
if (t1 >= (s)) { \
(a) = (c)(dpos); \
dpos += (s); \
+ } else if (t1 = nfsm_disct(&md, &dpos, (s), t1, &cp2)) { \
+ error = t1; \
+ m_freem(mrep); \
+ goto nfsmout; \
} else { \
- error = nfsm_disct(&md, &dpos, (s), t1, &cp2); \
- if (error) { \
- m_freem(mrep); \
+ (a) = (c)cp2; \
+ } }
+
+#define nfsm_fhtom(v, v3) \
+ { if (v3) { \
+ t2 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; \
+ if (t2 <= M_TRAILINGSPACE(mb)) { \
+ nfsm_build(tl, u_long *, t2); \
+ *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize); \
+ *(tl + ((t2>>2) - 2)) = 0; \
+ bcopy((caddr_t)VTONFS(v)->n_fhp,(caddr_t)tl, \
+ VTONFS(v)->n_fhsize); \
+ } else if (t2 = nfsm_strtmbuf(&mb, &bpos, \
+ (caddr_t)VTONFS(v)->n_fhp, VTONFS(v)->n_fhsize)) { \
+ error = t2; \
+ m_freem(mreq); \
goto nfsmout; \
- } else { \
- (a) = (c)cp2; \
} \
+ } else { \
+ nfsm_build(cp, caddr_t, NFSX_V2FH); \
+ bcopy((caddr_t)VTONFS(v)->n_fhp, cp, NFSX_V2FH); \
} }
-#define nfsm_fhtom(v) \
- nfsm_build(cp,caddr_t,NFSX_FH); \
- bcopy((caddr_t)&(VTONFS(v)->n_fh), cp, NFSX_FH)
+#define nfsm_srvfhtom(f, v3) \
+ { if (v3) { \
+ nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FH); \
+ *tl++ = txdr_unsigned(NFSX_V3FH); \
+ bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \
+ } else { \
+ nfsm_build(cp, caddr_t, NFSX_V2FH); \
+ bcopy((caddr_t)(f), cp, NFSX_V2FH); \
+ } }
-#define nfsm_srvfhtom(f) \
- nfsm_build(cp,caddr_t,NFSX_FH); \
- bcopy((caddr_t)(f), cp, NFSX_FH)
+#define nfsm_srvpostop_fh(f) \
+ { nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED + NFSX_V3FH); \
+ *tl++ = nfs_true; \
+ *tl++ = txdr_unsigned(NFSX_V3FH); \
+ bcopy((caddr_t)(f), (caddr_t)tl, NFSX_V3FH); \
+ }
-#define nfsm_mtofh(d,v) \
- { struct nfsnode *np; nfsv2fh_t *fhp; \
- nfsm_dissect(fhp,nfsv2fh_t *,NFSX_FH); \
- error = nfs_nget((d)->v_mount, fhp, &np); \
- if (error) { \
- m_freem(mrep); \
- goto nfsmout; \
+#define nfsm_mtofh(d, v, v3, f) \
+ { struct nfsnode *ttnp; nfsfh_t *ttfhp; int ttfhsize; \
+ if (v3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (f) = fxdr_unsigned(int, *tl); \
+ } else \
+ (f) = 1; \
+ if (f) { \
+ nfsm_getfh(ttfhp, ttfhsize, (v3)); \
+ if (t1 = nfs_nget((d)->v_mount, ttfhp, ttfhsize, \
+ &ttnp)) { \
+ error = t1; \
+ m_freem(mrep); \
+ goto nfsmout; \
+ } \
+ (v) = NFSTOV(ttnp); \
+ } \
+ if (v3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (f) \
+ (f) = fxdr_unsigned(int, *tl); \
+ else if (fxdr_unsigned(int, *tl)) \
+ nfsm_adv(NFSX_V3FATTR); \
} \
- (v) = NFSTOV(np); \
- nfsm_loadattr(v, (struct vattr *)0); \
+ if (f) \
+ nfsm_loadattr((v), (struct vattr *)0); \
}
-#define nfsm_loadattr(v,a) \
- { struct vnode *tvp = (v); \
- error = nfs_loadattrcache(&tvp, &md, &dpos, (a)); \
- if (error) { \
+#define nfsm_getfh(f, s, v3) \
+ { if (v3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (((s) = fxdr_unsigned(int, *tl)) <= 0 || \
+ (s) > NFSX_V3FHMAX) { \
+ m_freem(mrep); \
+ error = EBADRPC; \
+ goto nfsmout; \
+ } \
+ } else \
+ (s) = NFSX_V2FH; \
+ nfsm_dissect((f), nfsfh_t *, nfsm_rndup(s)); }
+
+#define nfsm_loadattr(v, a) \
+ { struct vnode *ttvp = (v); \
+ if (t1 = nfs_loadattrcache(&ttvp, &md, &dpos, (a))) { \
+ error = t1; \
m_freem(mrep); \
goto nfsmout; \
} \
- (v) = tvp; }
+ (v) = ttvp; }
+
+#define nfsm_postop_attr(v, f) \
+ { struct vnode *ttvp = (v); \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if ((f) = fxdr_unsigned(int, *tl)) { \
+ if (t1 = nfs_loadattrcache(&ttvp, &md, &dpos, \
+ (struct vattr *)0)) { \
+ error = t1; \
+ (f) = 0; \
+ m_freem(mrep); \
+ goto nfsmout; \
+ } \
+ (v) = ttvp; \
+ } }
+
+/* Used as (f) for nfsm_wcc_data() */
+#define NFSV3_WCCRATTR 0
+#define NFSV3_WCCCHK 1
+
+#define nfsm_wcc_data(v, f) \
+ { int ttattrf, ttretf = 0; \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED); \
+ if (f) \
+ ttretf = (VTONFS(v)->n_mtime == \
+ fxdr_unsigned(u_long, *(tl + 2))); \
+ } \
+ nfsm_postop_attr((v), ttattrf); \
+ if (f) { \
+ (f) = ttretf; \
+ } else { \
+ (f) = ttattrf; \
+ } }
+
+#define nfsm_v3sattr(s, a, u, g) \
+ { (s)->sa_modetrue = nfs_true; \
+ (s)->sa_mode = vtonfsv3_mode((a)->va_mode); \
+ (s)->sa_uidtrue = nfs_true; \
+ (s)->sa_uid = txdr_unsigned(u); \
+ (s)->sa_gidtrue = nfs_true; \
+ (s)->sa_gid = txdr_unsigned(g); \
+ (s)->sa_sizefalse = nfs_false; \
+ (s)->sa_atimetype = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); \
+ txdr_nfsv3time(&(a)->va_atime, &(s)->sa_atime); \
+ (s)->sa_mtimetype = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); \
+ txdr_nfsv3time(&(a)->va_mtime, &(s)->sa_mtime); \
+ }
#define nfsm_strsiz(s,m) \
{ nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \
@@ -149,16 +254,27 @@ extern struct mbuf *nfsm_reqh();
nfsm_reply(0); \
} }
+#define nfsm_srvnamesiz(s) \
+ { nfsm_dissect(tl,u_long *,NFSX_UNSIGNED); \
+ if (((s) = fxdr_unsigned(long,*tl)) > NFS_MAXNAMLEN) \
+ error = NFSERR_NAMETOL; \
+ if ((s) <= 0) \
+ error = EBADRPC; \
+ if (error) \
+ nfsm_reply(0); \
+ }
+
#define nfsm_mtouio(p,s) \
if ((s) > 0 && \
- (error = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \
+ (t1 = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \
+ error = t1; \
m_freem(mrep); \
goto nfsmout; \
}
#define nfsm_uiotom(p,s) \
- error = nfsm_uiotombuf((p),&mb,(s),&bpos); \
- if (error) { \
+ if (t1 = nfsm_uiotombuf((p),&mb,(s),&bpos)) { \
+ error = t1; \
m_freem(mreq); \
goto nfsmout; \
}
@@ -172,10 +288,13 @@ extern struct mbuf *nfsm_reqh();
#define nfsm_rndup(a) (((a)+3)&(~0x3))
#define nfsm_request(v, t, p, c) \
- error = nfs_request((v), mreq, (t), (p), \
- (c), &mrep, &md, &dpos); \
- if (error) \
- goto nfsmout
+ if (error = nfs_request((v), mreq, (t), (p), \
+ (c), &mrep, &md, &dpos)) { \
+ if (error & NFSERR_RETERR) \
+ error &= ~NFSERR_RETERR; \
+ else \
+ goto nfsmout; \
+ }
#define nfsm_strtom(a,s,m) \
if ((s) > (m)) { \
@@ -189,12 +308,10 @@ extern struct mbuf *nfsm_reqh();
*tl++ = txdr_unsigned(s); \
*(tl+((t2>>2)-2)) = 0; \
bcopy((caddr_t)(a), (caddr_t)tl, (s)); \
- } else { \
- error = nfsm_strtmbuf(&mb, &bpos, (a), (s)); \
- if (error) { \
- m_freem(mreq); \
- goto nfsmout; \
- } \
+ } else if (t2 = nfsm_strtmbuf(&mb, &bpos, (a), (s))) { \
+ error = t2; \
+ m_freem(mreq); \
+ goto nfsmout; \
}
#define nfsm_srvdone \
@@ -204,33 +321,53 @@ extern struct mbuf *nfsm_reqh();
#define nfsm_reply(s) \
{ \
nfsd->nd_repstat = error; \
- if (error) \
- (void) nfs_rephead(0, nfsd, error, cache, &frev, \
+ if (error && !(nfsd->nd_flag & ND_NFSV3)) \
+ (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \
mrq, &mb, &bpos); \
else \
- (void) nfs_rephead((s), nfsd, error, cache, &frev, \
+ (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \
mrq, &mb, &bpos); \
m_freem(mrep); \
mreq = *mrq; \
- if (error) \
+ if (error && (!(nfsd->nd_flag & ND_NFSV3) || \
+ error == EBADRPC)) \
return(0); \
}
+#define nfsm_writereply(s, v3) \
+ { \
+ nfsd->nd_repstat = error; \
+ if (error && !(v3)) \
+ (void) nfs_rephead(0, nfsd, slp, error, cache, &frev, \
+ &mreq, &mb, &bpos); \
+ else \
+ (void) nfs_rephead((s), nfsd, slp, error, cache, &frev, \
+ &mreq, &mb, &bpos); \
+ }
+
#define nfsm_adv(s) \
- t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+ { t1 = mtod(md, caddr_t)+md->m_len-dpos; \
if (t1 >= (s)) { \
dpos += (s); \
- } else { \
- error = nfs_adv(&md, &dpos, (s), t1); \
- if (error) { \
- m_freem(mrep); \
- goto nfsmout; \
- } \
- }
+ } else if (t1 = nfs_adv(&md, &dpos, (s), t1)) { \
+ error = t1; \
+ m_freem(mrep); \
+ goto nfsmout; \
+ } }
#define nfsm_srvmtofh(f) \
- nfsm_dissect(tl, u_long *, NFSX_FH); \
- bcopy((caddr_t)tl, (caddr_t)f, NFSX_FH)
+ { if (nfsd->nd_flag & ND_NFSV3) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \
+ error = EBADRPC; \
+ nfsm_reply(0); \
+ } \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_V3FH); \
+ bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \
+ if ((nfsd->nd_flag & ND_NFSV3) == 0) \
+ nfsm_adv(NFSX_V2FH - NFSX_V3FH); \
+ }
#define nfsm_clget \
if (bp >= be) { \
@@ -246,41 +383,57 @@ extern struct mbuf *nfsm_reqh();
} \
tl = (u_long *)bp
-#define nfsm_srvfillattr \
- fp->fa_type = vtonfs_type(vap->va_type); \
- fp->fa_mode = vtonfs_mode(vap->va_type, vap->va_mode); \
- fp->fa_nlink = txdr_unsigned(vap->va_nlink); \
- fp->fa_uid = txdr_unsigned(vap->va_uid); \
- fp->fa_gid = txdr_unsigned(vap->va_gid); \
- if (nfsd->nd_nqlflag == NQL_NOVAL) { \
- fp->fa_nfsblocksize = txdr_unsigned(vap->va_blocksize); \
- if (vap->va_type == VFIFO) \
- fp->fa_nfsrdev = 0xffffffff; \
- else \
- fp->fa_nfsrdev = txdr_unsigned(vap->va_rdev); \
- fp->fa_nfsfsid = txdr_unsigned(vap->va_fsid); \
- fp->fa_nfsfileid = txdr_unsigned(vap->va_fileid); \
- fp->fa_nfssize = txdr_unsigned(vap->va_size); \
- fp->fa_nfsblocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); \
- txdr_nfstime(&vap->va_atime, &fp->fa_nfsatime); \
- txdr_nfstime(&vap->va_mtime, &fp->fa_nfsmtime); \
- txdr_nfstime(&vap->va_ctime, &fp->fa_nfsctime); \
- } else { \
- fp->fa_nqblocksize = txdr_unsigned(vap->va_blocksize); \
- if (vap->va_type == VFIFO) \
- fp->fa_nqrdev = 0xffffffff; \
- else \
- fp->fa_nqrdev = txdr_unsigned(vap->va_rdev); \
- fp->fa_nqfsid = txdr_unsigned(vap->va_fsid); \
- fp->fa_nqfileid = txdr_unsigned(vap->va_fileid); \
- txdr_hyper(&vap->va_size, &fp->fa_nqsize); \
- txdr_hyper(&vap->va_bytes, &fp->fa_nqbytes); \
- txdr_nqtime(&vap->va_atime, &fp->fa_nqatime); \
- txdr_nqtime(&vap->va_mtime, &fp->fa_nqmtime); \
- txdr_nqtime(&vap->va_ctime, &fp->fa_nqctime); \
- fp->fa_nqflags = txdr_unsigned(vap->va_flags); \
- fp->fa_nqgen = txdr_unsigned(vap->va_gen); \
- txdr_hyper(&vap->va_filerev, &fp->fa_nqfilerev); \
- }
+#define nfsm_srvfillattr(a, f) \
+ nfsm_srvfattr(nfsd, (a), (f))
+
+#define nfsm_srvwcc_data(br, b, ar, a) \
+ nfsm_srvwcc(nfsd, (br), (b), (ar), (a), &mb, &bpos)
+
+#define nfsm_srvpostop_attr(r, a) \
+ nfsm_srvpostopattr(nfsd, (r), (a), &mb, &bpos)
+
+#define nfsm_srvsattr(a) \
+ { nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (a)->va_mode = nfstov_mode(*tl); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (a)->va_uid = fxdr_unsigned(uid_t, *tl); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ (a)->va_gid = fxdr_unsigned(gid_t, *tl); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ if (*tl == nfs_true) { \
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \
+ fxdr_hyper(tl, &(a)->va_size); \
+ } \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ switch (fxdr_unsigned(int, *tl)) { \
+ case NFSV3SATTRTIME_TOCLIENT: \
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \
+ fxdr_nfsv3time(tl, &(a)->va_atime); \
+ break; \
+ case NFSV3SATTRTIME_TOSERVER: \
+ (a)->va_atime.ts_sec = time.tv_sec; \
+ (a)->va_atime.ts_nsec = time.tv_usec * 1000; \
+ break; \
+ }; \
+ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \
+ switch (fxdr_unsigned(int, *tl)) { \
+ case NFSV3SATTRTIME_TOCLIENT: \
+ nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED); \
+ fxdr_nfsv3time(tl, &(a)->va_mtime); \
+ break; \
+ case NFSV3SATTRTIME_TOSERVER: \
+ (a)->va_mtime.ts_sec = time.tv_sec; \
+ (a)->va_mtime.ts_nsec = time.tv_usec * 1000; \
+ break; \
+ }; }
#endif
diff --git a/sys/nfs/nfsmount.h b/sys/nfs/nfsmount.h
index 99a1b48795f4..6ac33f778c82 100644
--- a/sys/nfs/nfsmount.h
+++ b/sys/nfs/nfsmount.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfsmount.h 8.1 (Berkeley) 6/10/93
- * $Id: nfsmount.h,v 1.3 1994/08/21 06:50:10 paul Exp $
+ * $Id: nfsmount.h,v 1.4 1994/10/17 17:47:43 phk Exp $
*/
#ifndef _NFS_NFSMOUNT_H_
@@ -49,7 +49,8 @@ struct nfsmount {
int nm_flag; /* Flags for soft/hard... */
struct mount *nm_mountp; /* Vfs structure for this filesystem */
int nm_numgrps; /* Max. size of groupslist */
- nfsv2fh_t nm_fh; /* File handle of root dir */
+ u_char nm_fh[NFSX_V3FHMAX]; /* File handle of root dir */
+ int nm_fhsize; /* Size of root file handle */
struct socket *nm_so; /* Rpc socket */
int nm_sotype; /* Type of socket */
int nm_soproto; /* and protocol */
@@ -65,6 +66,7 @@ struct nfsmount {
int nm_deadthresh; /* Threshold of timeouts-->dead server*/
int nm_rsize; /* Max size of read rpc */
int nm_wsize; /* Max size of write rpc */
+ int nm_readdirsize; /* Size of a readdir rpc */
int nm_readahead; /* Num. of blocks to readahead */
int nm_leaseterm; /* Term (sec) for NQNFS lease */
CIRCLEQ_HEAD(, nfsnode) nm_timerhead; /* Head of lease timer queue */
@@ -73,9 +75,16 @@ struct nfsmount {
int nm_authtype; /* Authenticator type */
int nm_authlen; /* and length */
char *nm_authstr; /* Authenticator string */
+ char *nm_verfstr; /* and the verifier */
+ int nm_verflen;
+ u_char nm_verf[NFSX_V3WRITEVERF]; /* V3 write verifier */
+ NFSKERBKEY_T nm_key; /* and the session key */
+ int nm_numuids; /* Number of nfsuid mappings */
+ TAILQ_HEAD(, nfsuid) nm_uidlruhead; /* Lists of nfsuid mappings */
+ LIST_HEAD(, nfsuid) nm_uidhashtbl[NFS_MUIDHASHSIZ];
};
-#ifdef KERNEL
+#if defined(KERNEL) || defined(_KERNEL)
/*
* Convert mount ptr to nfsmount ptr.
*/
diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h
index dc9162b061cc..18dbde21ece1 100644
--- a/sys/nfs/nfsnode.h
+++ b/sys/nfs/nfsnode.h
@@ -34,12 +34,16 @@
* SUCH DAMAGE.
*
* @(#)nfsnode.h 8.4 (Berkeley) 2/13/94
- * $Id: nfsnode.h,v 1.8 1994/10/17 17:47:44 phk Exp $
+ * $Id: nfsnode.h,v 1.9 1995/03/16 18:15:42 bde Exp $
*/
#ifndef _NFS_NFSNODE_H_
#define _NFS_NFSNODE_H_
+#ifndef _NFS_NFS_H_
+#include <nfs/nfs.h>
+#endif
+
/*
* Silly rename structure that hangs off the nfsnode until the name
* can be removed by nfs_inactive()
@@ -52,36 +56,73 @@ struct sillyrename {
};
/*
+ * This structure is used to save the logical directory offset to
+ * NFS cookie mappings.
+ * The mappings are stored in a list headed
+ * by n_cookies, as required.
+ * There is one mapping for each NFS_DIRBLKSIZ bytes of directory information
+ * stored in increasing logical offset byte order.
+ */
+#define NFSNUMCOOKIES 31
+
+struct nfsdmap {
+ LIST_ENTRY(nfsdmap) ndm_list;
+ int ndm_eocookie;
+ nfsuint64 ndm_cookies[NFSNUMCOOKIES];
+};
+
+/*
* The nfsnode is the nfs equivalent to ufs's inode. Any similarity
* is purely coincidental.
* There is a unique nfsnode allocated for each active file,
* each current directory, each mounted-on file, text file, and the root.
* An nfsnode is 'named' by its file handle. (nget/nfs_node.c)
+ * If this structure exceeds 256 bytes (it is currently 256 using 4.4BSD-Lite
+ * type definitions), file handles of > 32 bytes should probably be split out
+ * into a separate MALLOC()'d data structure. (Reduce the size of nfsfh_t by
+ * changing the definition in sys/mount.h of NFS_SMALLFH.)
+ * NB: Hopefully the current order of the fields is such that everything will
+ * be well aligned and, therefore, tightly packed.
*/
-
struct nfsnode {
- LIST_ENTRY(nfsnode) n_hash; /* Hash chain */
- CIRCLEQ_ENTRY(nfsnode) n_timer; /* Nqnfs timer chain */
- nfsv2fh_t n_fh; /* NFS File Handle */
- long n_flag; /* Flag for locking.. */
- struct vnode *n_vnode; /* vnode associated with this node */
- struct vattr n_vattr; /* Vnode attribute cache */
- time_t n_attrstamp; /* Time stamp for cached attributes */
- struct sillyrename *n_sillyrename; /* Ptr to silly rename struct */
- u_quad_t n_size; /* Current size of file */
- struct lockf *n_lockf; /* Locking record of file */
- int n_error; /* Save write error value */
- u_long n_direofoffset; /* Dir. EOF offset cache */
- time_t n_mtime; /* Prev modify time. */
- time_t n_ctime; /* Prev create time. */
- u_quad_t n_brev; /* Modify rev when cached */
- u_quad_t n_lrev; /* Modify rev for lease */
- time_t n_expiry; /* Lease expiry time */
- struct sillyrename n_silly; /* Silly rename struct */
- struct timeval n_atim; /* Special file times */
- struct timeval n_mtim;
+ LIST_ENTRY(nfsnode) n_hash; /* Hash chain */
+ CIRCLEQ_ENTRY(nfsnode) n_timer; /* Nqnfs timer chain */
+ u_quad_t n_size; /* Current size of file */
+ u_quad_t n_brev; /* Modify rev when cached */
+ u_quad_t n_lrev; /* Modify rev for lease */
+ struct vattr n_vattr; /* Vnode attribute cache */
+ time_t n_attrstamp; /* Attr. cache timestamp */
+ time_t n_mtime; /* Prev modify time. */
+ time_t n_ctime; /* Prev create time. */
+ time_t n_expiry; /* Lease expiry time */
+ nfsfh_t *n_fhp; /* NFS File Handle */
+ struct vnode *n_vnode; /* associated vnode */
+ struct lockf *n_lockf; /* Locking record of file */
+ int n_error; /* Save write error value */
+ union {
+ struct timespec nf_atim; /* Special file times */
+ nfsuint64 nd_cookieverf; /* Cookie verifier (dir only) */
+ } n_un1;
+ union {
+ struct timespec nf_mtim;
+ off_t nd_direof; /* Dir. EOF offset cache */
+ } n_un2;
+ union {
+ struct sillyrename *nf_silly; /* Ptr to silly rename struct */
+ LIST_HEAD(, nfsdmap) nd_cook; /* cookies */
+ } n_un3;
+ short n_fhsize; /* size in bytes, of fh */
+ short n_flag; /* Flag for locking.. */
+ nfsfh_t n_fh; /* Small File Handle */
};
+#define n_atim n_un1.nf_atim
+#define n_mtim n_un2.nf_mtim
+#define n_sillyrename n_un3.nf_silly
+#define n_cookieverf n_un1.nd_cookieverf
+#define n_direofoffset n_un2.nd_direof
+#define n_cookies n_un3.nd_cook
+
/*
* Flags for n_flag
*/
@@ -95,6 +136,8 @@ struct nfsnode {
#define NACC 0x0100 /* Special file accessed */
#define NUPD 0x0200 /* Special file updated */
#define NCHG 0x0400 /* Special file times changed */
+#define NLOCKED 0x0800 /* node is locked */
+#define NWANTED 0x0100 /* someone wants to lock */
/*
* Convert between nfsnode pointers and vnode pointers
@@ -107,7 +150,7 @@ struct nfsnode {
*/
TAILQ_HEAD(, buf) nfs_bufq;
-#ifdef KERNEL
+#if defined(KERNEL) || defined(_KERNEL)
extern int (**fifo_nfsv2nodeop_p)();
extern int (**nfsv2_vnodeop_p)();
extern int (**spec_nfsv2nodeop_p)();
@@ -128,12 +171,25 @@ int nfs_getattr __P((struct vop_getattr_args *));
int nfs_setattr __P((struct vop_setattr_args *));
int nfs_read __P((struct vop_read_args *));
int nfs_write __P((struct vop_write_args *));
+#ifdef HAS_VOPLEASE
+#define nfs_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
+#define nqnfs_vop_lease_check lease_check
+#else
+#ifdef __FreeBSD__
+#define nqnfs_lease_check nfs_lease_check
+#else
+#define nqnfs_lease_check lease_check
+#endif
+#endif
int nfsspec_read __P((struct vop_read_args *));
int nfsspec_write __P((struct vop_write_args *));
int nfsfifo_read __P((struct vop_read_args *));
int nfsfifo_write __P((struct vop_write_args *));
#define nfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))enoioctl)
#define nfs_select ((int (*) __P((struct vop_select_args *)))seltrue)
+#ifdef HAS_VOPREVOKE
+#define nfs_revoke vop_revoke
+#endif
int nfs_mmap __P((struct vop_mmap_args *));
int nfs_fsync __P((struct vop_fsync_args *));
#define nfs_seek ((int (*) __P((struct vop_seek_args *)))nullop)
@@ -157,6 +213,7 @@ int nfs_islocked __P((struct vop_islocked_args *));
int nfs_pathconf __P((struct vop_pathconf_args *));
int nfs_advlock __P((struct vop_advlock_args *));
int nfs_blkatoff __P((struct vop_blkatoff_args *));
+int nfs_bwrite __P((struct vop_bwrite_args *));
int nfs_vget __P((struct mount *, ino_t, struct vnode **));
int nfs_valloc __P((struct vop_valloc_args *));
#define nfs_reallocblks \
@@ -164,13 +221,20 @@ int nfs_valloc __P((struct vop_valloc_args *));
int nfs_vfree __P((struct vop_vfree_args *));
int nfs_truncate __P((struct vop_truncate_args *));
int nfs_update __P((struct vop_update_args *));
-int nfs_bwrite __P((struct vop_bwrite_args *));
/* other stuff */
int nfs_removeit __P((struct sillyrename *));
-int nfs_nget __P((struct mount *,nfsv2fh_t *,struct nfsnode **));
-int nfs_lookitup __P((struct sillyrename *,nfsv2fh_t *,struct proc *));
+int nfs_nget __P((struct mount *,nfsfh_t *,int,struct nfsnode **));
+int nfs_lookitup __P((struct vnode *,char *,int,struct ucred *,struct proc *,struct nfsnode **));
int nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *));
+nfsuint64 *nfs_getcookie __P((struct nfsnode *, off_t, int));
+void nfs_invaldir __P((struct vnode *));
+
+#ifdef __FreeBSD__
+#define nqnfs_lease_updatetime nfs_lease_updatetime
+#else
+#define nqnfs_lease_updatetime lease_updatetime
+#endif
#endif /* KERNEL */
diff --git a/sys/nfs/nfsproto.h b/sys/nfs/nfsproto.h
new file mode 100644
index 000000000000..ac1a09075c3e
--- /dev/null
+++ b/sys/nfs/nfsproto.h
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nfsproto.h 8.1 (Berkeley) 6/10/93
+ * $Id: nfsproto.h,v 1.4 1994/08/21 06:50:13 paul Exp $
+ */
+
+#ifndef _NFS_NFSPROTO_H_
+#define _NFS_NFSPROTO_H_
+
+/*
+ * nfs definitions as per the Version 2 and 3 specs
+ */
+
+/*
+ * Constants as defined in the Sun NFS Version 2 and 3 specs.
+ * "NFS: Network File System Protocol Specification" RFC1094
+ * and in the "NFS: Network File System Version 3 Protocol
+ * Specification"
+ */
+
+#define NFS_PORT 2049
+#define NFS_PROG 100003
+#define NFS_VER2 2
+#define NFS_VER3 3
+#define NFS_V2MAXDATA 8192
+#define NFS_MAXDGRAMDATA 16384
+#define NFS_MAXDATA 32768
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_MAXPKTHDR 404
+#define NFS_MAXPACKET (NFS_MAXPKTHDR + NFS_MAXDATA)
+#define NFS_MINPACKET 20
+#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */
+
+/* Stat numbers for rpc returns (version 2 and 3) */
+#define NFS_OK 0
+#define NFSERR_PERM 1
+#define NFSERR_NOENT 2
+#define NFSERR_IO 5
+#define NFSERR_NXIO 6
+#define NFSERR_ACCES 13
+#define NFSERR_EXIST 17
+#define NFSERR_XDEV 18 /* Version 3 only */
+#define NFSERR_NODEV 19
+#define NFSERR_NOTDIR 20
+#define NFSERR_ISDIR 21
+#define NFSERR_INVAL 22 /* Version 3 only */
+#define NFSERR_FBIG 27
+#define NFSERR_NOSPC 28
+#define NFSERR_ROFS 30
+#define NFSERR_MLINK 31 /* Version 3 only */
+#define NFSERR_NAMETOL 63
+#define NFSERR_NOTEMPTY 66
+#define NFSERR_DQUOT 69
+#define NFSERR_STALE 70
+#define NFSERR_REMOTE 71 /* Version 3 only */
+#define NFSERR_WFLUSH 99 /* Version 2 only */
+#define NFSERR_BADHANDLE 10001 /* The rest Version 3 only */
+#define NFSERR_NOT_SYNC 10002
+#define NFSERR_BAD_COOKIE 10003
+#define NFSERR_NOTSUPP 10004
+#define NFSERR_TOOSMALL 10005
+#define NFSERR_SERVERFAULT 10006
+#define NFSERR_BADTYPE 10007
+#define NFSERR_JUKEBOX 10008
+#define NFSERR_TRYLATER NFSERR_JUKEBOX
+#define NFSERR_STALEWRITEVERF 30001 /* Fake return for nfs_commit() */
+
+#define NFSERR_RETVOID 0x20000000 /* Return void, not error */
+#define NFSERR_AUTHERR 0x40000000 /* Mark an authentication error */
+#define NFSERR_RETERR 0x80000000 /* Mark an error return for V3 */
+
+/* Sizes in bytes of various nfs rpc components */
+#define NFSX_UNSIGNED 4
+
+/* specific to NFS Version 2 */
+#define NFSX_V2FH 32
+#define NFSX_V2FATTR 68
+#define NFSX_V2SATTR 32
+#define NFSX_V2COOKIE 4
+#define NFSX_V2STATFS 20
+
+/* specific to NFS Version 3 */
+#define NFSX_V3FH (sizeof (fhandle_t)) /* size this server uses */
+#define NFSX_V3FHMAX 64 /* max. allowed by protocol */
+#define NFSX_V3FATTR 84
+#define NFSX_V3SATTR 60 /* max. all fields filled in */
+#define NFSX_V3SRVSATTR (sizeof (struct nfsv3_sattr))
+#define NFSX_V3POSTOPATTR (NFSX_V3FATTR + NFSX_UNSIGNED)
+#define NFSX_V3WCCDATA (NFSX_V3POSTOPATTR + 8 * NFSX_UNSIGNED)
+#define NFSX_V3COOKIEVERF 8
+#define NFSX_V3WRITEVERF 8
+#define NFSX_V3CREATEVERF 8
+#define NFSX_V3STATFS 52
+#define NFSX_V3FSINFO 48
+#define NFSX_V3PATHCONF 24
+
+/* variants for both versions */
+#define NFSX_FH(v3) ((v3) ? (NFSX_V3FHMAX + NFSX_UNSIGNED) : \
+ NFSX_V2FH)
+#define NFSX_SRVFH(v3) ((v3) ? NFSX_V3FH : NFSX_V2FH)
+#define NFSX_FATTR(v3) ((v3) ? NFSX_V3FATTR : NFSX_V2FATTR)
+#define NFSX_PREOPATTR(v3) ((v3) ? (7 * NFSX_UNSIGNED) : 0)
+#define NFSX_POSTOPATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : 0)
+#define NFSX_POSTOPORFATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : \
+ NFSX_V2FATTR)
+#define NFSX_WCCDATA(v3) ((v3) ? NFSX_V3WCCDATA : 0)
+#define NFSX_WCCORFATTR(v3) ((v3) ? NFSX_V3WCCDATA : NFSX_V2FATTR)
+#define NFSX_SATTR(v3) ((v3) ? NFSX_V3SATTR : NFSX_V2SATTR)
+#define NFSX_COOKIEVERF(v3) ((v3) ? NFSX_V3COOKIEVERF : 0)
+#define NFSX_WRITEVERF(v3) ((v3) ? NFSX_V3WRITEVERF : 0)
+#define NFSX_READDIR(v3) ((v3) ? (5 * NFSX_UNSIGNED) : \
+ (2 * NFSX_UNSIGNED))
+#define NFSX_STATFS(v3) ((v3) ? NFSX_V3STATFS : NFSX_V2STATFS)
+
+/* nfs rpc procedure numbers (before version mapping) */
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_LOOKUP 3
+#define NFSPROC_ACCESS 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITE 7
+#define NFSPROC_CREATE 8
+#define NFSPROC_MKDIR 9
+#define NFSPROC_SYMLINK 10
+#define NFSPROC_MKNOD 11
+#define NFSPROC_REMOVE 12
+#define NFSPROC_RMDIR 13
+#define NFSPROC_RENAME 14
+#define NFSPROC_LINK 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_READDIRPLUS 17
+#define NFSPROC_FSSTAT 18
+#define NFSPROC_FSINFO 19
+#define NFSPROC_PATHCONF 20
+#define NFSPROC_COMMIT 21
+
+/* And leasing (nqnfs) procedure numbers (must be last) */
+#define NQNFSPROC_GETLEASE 22
+#define NQNFSPROC_VACATED 23
+#define NQNFSPROC_EVICTED 24
+
+#define NFSPROC_NOOP 25
+#define NFS_NPROCS 26
+
+/* Actual Version 2 procedure numbers */
+#define NFSV2PROC_NULL 0
+#define NFSV2PROC_GETATTR 1
+#define NFSV2PROC_SETATTR 2
+#define NFSV2PROC_NOOP 3
+#define NFSV2PROC_ROOT NFSV2PROC_NOOP /* Obsolete */
+#define NFSV2PROC_LOOKUP 4
+#define NFSV2PROC_READLINK 5
+#define NFSV2PROC_READ 6
+#define NFSV2PROC_WRITECACHE NFSV2PROC_NOOP /* Obsolete */
+#define NFSV2PROC_WRITE 8
+#define NFSV2PROC_CREATE 9
+#define NFSV2PROC_REMOVE 10
+#define NFSV2PROC_RENAME 11
+#define NFSV2PROC_LINK 12
+#define NFSV2PROC_SYMLINK 13
+#define NFSV2PROC_MKDIR 14
+#define NFSV2PROC_RMDIR 15
+#define NFSV2PROC_READDIR 16
+#define NFSV2PROC_STATFS 17
+
+/*
+ * Constants used by the Version 3 protocol for various RPCs
+ */
+#define NFSV3SATTRTIME_DONTCHANGE 0
+#define NFSV3SATTRTIME_TOSERVER 1
+#define NFSV3SATTRTIME_TOCLIENT 2
+
+#define NFSV3ACCESS_READ 0x01
+#define NFSV3ACCESS_LOOKUP 0x02
+#define NFSV3ACCESS_MODIFY 0x04
+#define NFSV3ACCESS_EXTEND 0x08
+#define NFSV3ACCESS_DELETE 0x10
+#define NFSV3ACCESS_EXECUTE 0x20
+
+#define NFSV3WRITE_UNSTABLE 0
+#define NFSV3WRITE_DATASYNC 1
+#define NFSV3WRITE_FILESYNC 2
+
+#define NFSV3CREATE_UNCHECKED 0
+#define NFSV3CREATE_GUARDED 1
+#define NFSV3CREATE_EXCLUSIVE 2
+
+#define NFSV3FSINFO_LINK 0x01
+#define NFSV3FSINFO_SYMLINK 0x02
+#define NFSV3FSINFO_HOMOGENEOUS 0x08
+#define NFSV3FSINFO_CANSETTIME 0x10
+
+/* Conversion macros */
+#define vtonfsv2_mode(t,m) \
+ txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \
+ MAKEIMODE((t), (m)))
+#define vtonfsv3_mode(m) txdr_unsigned((m) & 07777)
+#define nfstov_mode(a) (fxdr_unsigned(u_short, (a))&07777)
+#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((long)(a))])
+#define vtonfsv3_type(a) txdr_unsigned(nfsv3_type[((long)(a))])
+#define nfsv2tov_type(a) nv2tov_type[fxdr_unsigned(u_long,(a))&0x7]
+#define nfsv3tov_type(a) nv3tov_type[fxdr_unsigned(u_long,(a))&0x7]
+
+/* File types */
+typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5,
+ NFSOCK=6, NFFIFO=7 } nfstype;
+
+/* Structs for common parts of the rpc's */
+/*
+ * File Handle (32 bytes for version 2), variable up to 64 for version 3.
+ * File Handles of up to NFS_SMALLFH in size are stored directly in the
+ * nfs node, whereas larger ones are malloc'd. (This never happens when
+ * NFS_SMALLFH is set to 64.)
+ * NFS_SMALLFH should be in the range of 32 to 64 and be divisible by 4.
+ */
+#ifndef NFS_SMALLFH
+#define NFS_SMALLFH 64
+#endif
+union nfsfh {
+ fhandle_t fh_generic;
+ u_char fh_bytes[NFS_SMALLFH];
+};
+typedef union nfsfh nfsfh_t;
+
+struct nfsv2_time {
+ u_long nfsv2_sec;
+ u_long nfsv2_usec;
+};
+typedef struct nfsv2_time nfstime2;
+
+struct nfsv3_time {
+ u_long nfsv3_sec;
+ u_long nfsv3_nsec;
+};
+typedef struct nfsv3_time nfstime3;
+
+/*
+ * Quads are defined as arrays of 2 longs to ensure dense packing for the
+ * protocol and to facilitate xdr conversion.
+ */
+struct nfs_uquad {
+ u_long nfsuquad[2];
+};
+typedef struct nfs_uquad nfsuint64;
+
+/*
+ * Used to convert between two u_longs and a u_quad_t.
+ */
+union nfs_quadconvert {
+ u_long lval[2];
+ u_quad_t qval;
+};
+typedef union nfs_quadconvert nfsquad_t;
+
+/*
+ * NFS Version 3 special file number.
+ */
+struct nfsv3_spec {
+ u_long specdata1;
+ u_long specdata2;
+};
+typedef struct nfsv3_spec nfsv3spec;
+
+/*
+ * File attributes and setable attributes. These structures cover both
+ * NFS version 2 and the version 3 protocol. Note that the union is only
+ * used so that one pointer can refer to both variants. These structures
+ * go out on the wire and must be densely packed, so no quad data types
+ * are used. (all fields are longs or u_longs or structures of same)
+ * NB: You can't do sizeof(struct nfs_fattr), you must use the
+ * NFSX_FATTR(v3) macro.
+ */
+struct nfs_fattr {
+ u_long fa_type;
+ u_long fa_mode;
+ u_long fa_nlink;
+ u_long fa_uid;
+ u_long fa_gid;
+ union {
+ struct {
+ u_long nfsv2fa_size;
+ u_long nfsv2fa_blocksize;
+ u_long nfsv2fa_rdev;
+ u_long nfsv2fa_blocks;
+ u_long nfsv2fa_fsid;
+ u_long nfsv2fa_fileid;
+ nfstime2 nfsv2fa_atime;
+ nfstime2 nfsv2fa_mtime;
+ nfstime2 nfsv2fa_ctime;
+ } fa_nfsv2;
+ struct {
+ nfsuint64 nfsv3fa_size;
+ nfsuint64 nfsv3fa_used;
+ nfsv3spec nfsv3fa_rdev;
+ nfsuint64 nfsv3fa_fsid;
+ nfsuint64 nfsv3fa_fileid;
+ nfstime3 nfsv3fa_atime;
+ nfstime3 nfsv3fa_mtime;
+ nfstime3 nfsv3fa_ctime;
+ } fa_nfsv3;
+ } fa_un;
+};
+
+/* and some ugly defines for accessing union components */
+#define fa2_size fa_un.fa_nfsv2.nfsv2fa_size
+#define fa2_blocksize fa_un.fa_nfsv2.nfsv2fa_blocksize
+#define fa2_rdev fa_un.fa_nfsv2.nfsv2fa_rdev
+#define fa2_blocks fa_un.fa_nfsv2.nfsv2fa_blocks
+#define fa2_fsid fa_un.fa_nfsv2.nfsv2fa_fsid
+#define fa2_fileid fa_un.fa_nfsv2.nfsv2fa_fileid
+#define fa2_atime fa_un.fa_nfsv2.nfsv2fa_atime
+#define fa2_mtime fa_un.fa_nfsv2.nfsv2fa_mtime
+#define fa2_ctime fa_un.fa_nfsv2.nfsv2fa_ctime
+#define fa3_size fa_un.fa_nfsv3.nfsv3fa_size
+#define fa3_used fa_un.fa_nfsv3.nfsv3fa_used
+#define fa3_rdev fa_un.fa_nfsv3.nfsv3fa_rdev
+#define fa3_fsid fa_un.fa_nfsv3.nfsv3fa_fsid
+#define fa3_fileid fa_un.fa_nfsv3.nfsv3fa_fileid
+#define fa3_atime fa_un.fa_nfsv3.nfsv3fa_atime
+#define fa3_mtime fa_un.fa_nfsv3.nfsv3fa_mtime
+#define fa3_ctime fa_un.fa_nfsv3.nfsv3fa_ctime
+
+struct nfsv2_sattr {
+ u_long sa_mode;
+ u_long sa_uid;
+ u_long sa_gid;
+ u_long sa_size;
+ nfstime2 sa_atime;
+ nfstime2 sa_mtime;
+};
+
+/*
+ * NFS Version 3 sattr structure for the new node creation case.
+ */
+struct nfsv3_sattr {
+ u_long sa_modetrue;
+ u_long sa_mode;
+ u_long sa_uidtrue;
+ u_long sa_uid;
+ u_long sa_gidtrue;
+ u_long sa_gid;
+ u_long sa_sizefalse;
+ u_long sa_atimetype;
+ nfstime3 sa_atime;
+ u_long sa_mtimetype;
+ nfstime3 sa_mtime;
+};
+
+struct nfs_statfs {
+ union {
+ struct {
+ u_long nfsv2sf_tsize;
+ u_long nfsv2sf_bsize;
+ u_long nfsv2sf_blocks;
+ u_long nfsv2sf_bfree;
+ u_long nfsv2sf_bavail;
+ } sf_nfsv2;
+ struct {
+ nfsuint64 nfsv3sf_tbytes;
+ nfsuint64 nfsv3sf_fbytes;
+ nfsuint64 nfsv3sf_abytes;
+ nfsuint64 nfsv3sf_tfiles;
+ nfsuint64 nfsv3sf_ffiles;
+ nfsuint64 nfsv3sf_afiles;
+ u_long nfsv3sf_invarsec;
+ } sf_nfsv3;
+ } sf_un;
+};
+
+#define sf_tsize sf_un.sf_nfsv2.nfsv2sf_tsize
+#define sf_bsize sf_un.sf_nfsv2.nfsv2sf_bsize
+#define sf_blocks sf_un.sf_nfsv2.nfsv2sf_blocks
+#define sf_bfree sf_un.sf_nfsv2.nfsv2sf_bfree
+#define sf_bavail sf_un.sf_nfsv2.nfsv2sf_bavail
+#define sf_tbytes sf_un.sf_nfsv3.nfsv3sf_tbytes
+#define sf_fbytes sf_un.sf_nfsv3.nfsv3sf_fbytes
+#define sf_abytes sf_un.sf_nfsv3.nfsv3sf_abytes
+#define sf_tfiles sf_un.sf_nfsv3.nfsv3sf_tfiles
+#define sf_ffiles sf_un.sf_nfsv3.nfsv3sf_ffiles
+#define sf_afiles sf_un.sf_nfsv3.nfsv3sf_afiles
+#define sf_invarsec sf_un.sf_nfsv3.nfsv3sf_invarsec
+
+struct nfsv3_fsinfo {
+ u_long fs_rtmax;
+ u_long fs_rtpref;
+ u_long fs_rtmult;
+ u_long fs_wtmax;
+ u_long fs_wtpref;
+ u_long fs_wtmult;
+ u_long fs_dtpref;
+ nfsuint64 fs_maxfilesize;
+ nfstime3 fs_timedelta;
+ u_long fs_properties;
+};
+
+struct nfsv3_pathconf {
+ u_long pc_linkmax;
+ u_long pc_namemax;
+ u_long pc_notrunc;
+ u_long pc_chownrestricted;
+ u_long pc_caseinsensitive;
+ u_long pc_casepreserving;
+};
+
+#endif
diff --git a/sys/nfs/nfsrtt.h b/sys/nfs/nfsrtt.h
index 4463f621645d..38f520e9c954 100644
--- a/sys/nfs/nfsrtt.h
+++ b/sys/nfs/nfsrtt.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfsrtt.h 8.1 (Berkeley) 6/10/93
- * $Id: nfsrtt.h,v 1.2 1994/08/02 07:52:24 davidg Exp $
+ * $Id: nfsrtt.h,v 1.3 1994/08/21 06:50:12 paul Exp $
*/
#ifndef _NFS_NFSRTT_H_
@@ -82,6 +82,7 @@ struct nfsrtt {
#define DRT_TCP 0x02 /* Client used TCP transport */
#define DRT_CACHEREPLY 0x04 /* Reply was from recent request cache */
#define DRT_CACHEDROP 0x08 /* Rpc request dropped, due to recent reply */
+#define DRT_NFSV3 0x10 /* Rpc used NFS Version 3 */
/*
* Server log structure
diff --git a/sys/nfs/nfsrvcache.h b/sys/nfs/nfsrvcache.h
index b367b9f4a2c9..dc10bd746946 100644
--- a/sys/nfs/nfsrvcache.h
+++ b/sys/nfs/nfsrvcache.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfsrvcache.h 8.1 (Berkeley) 6/10/93
- * $Id: nfsrvcache.h,v 1.3 1994/08/21 06:50:13 paul Exp $
+ * $Id: nfsrvcache.h,v 1.4 1994/10/17 17:47:44 phk Exp $
*/
#ifndef _NFS_NFSRVCACHE_H_
@@ -44,7 +44,7 @@
* Definitions for the server recent request cache
*/
-#define NFSRVCACHESIZ 256
+#define NFSRVCACHESIZ 64
struct nfsrvcache {
TAILQ_ENTRY(nfsrvcache) rc_lru; /* LRU chain */
diff --git a/sys/nfs/nfsv2.h b/sys/nfs/nfsv2.h
index 62ba33899be1..1ae1a724d965 100644
--- a/sys/nfs/nfsv2.h
+++ b/sys/nfs/nfsv2.h
@@ -34,129 +34,201 @@
* SUCH DAMAGE.
*
* @(#)nfsv2.h 8.1 (Berkeley) 6/10/93
- * $Id: nfsv2.h,v 1.3 1994/08/18 22:35:37 wollman Exp $
+ * $Id: nfsv2.h,v 1.4 1994/08/21 06:50:13 paul Exp $
*/
-#ifndef _NFS_NFSV2_H_
-#define _NFS_NFSV2_H_
+#include <nfs/nfsproto.h>
+
+#if 0
+
/*
- * nfs definitions as per the version 2 specs
+ * nfs definitions as per the Version 2 and 3 specs
*/
/*
- * Constants as defined in the Sun NFS Version 2 spec.
+ * Constants as defined in the Sun NFS Version 2 and 3 specs.
* "NFS: Network File System Protocol Specification" RFC1094
+ * and in the "NFS: Network File System Version 3 Protocol
+ * Specification"
*/
#define NFS_PORT 2049
#define NFS_PROG 100003
#define NFS_VER2 2
+#define NFS_VER3 3
#define NFS_MAXDGRAMDATA 8192
#define NFS_MAXDATA 32768
#define NFS_MAXPATHLEN 1024
#define NFS_MAXNAMLEN 255
-#define NFS_FHSIZE 32
#define NFS_MAXPKTHDR 404
-#define NFS_MAXPACKET (NFS_MAXPKTHDR+NFS_MAXDATA)
+#define NFS_MAXPACKET (NFS_MAXPKTHDR + NFS_MAXDATA)
#define NFS_MINPACKET 20
#define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */
-/* Stat numbers for rpc returns */
-#define NFS_OK 0
-#define NFSERR_PERM 1
-#define NFSERR_NOENT 2
-#define NFSERR_IO 5
-#define NFSERR_NXIO 6
-#define NFSERR_ACCES 13
-#define NFSERR_EXIST 17
-#define NFSERR_NODEV 19
-#define NFSERR_NOTDIR 20
-#define NFSERR_ISDIR 21
-#define NFSERR_FBIG 27
-#define NFSERR_NOSPC 28
-#define NFSERR_ROFS 30
-#define NFSERR_NAMETOL 63
-#define NFSERR_NOTEMPTY 66
-#define NFSERR_DQUOT 69
-#define NFSERR_STALE 70
-#define NFSERR_WFLUSH 99
+/* Stat numbers for rpc returns (version 2 and 3) */
+#define NFS_OK 0
+#define NFSERR_PERM 1
+#define NFSERR_NOENT 2
+#define NFSERR_IO 5
+#define NFSERR_NXIO 6
+#define NFSERR_ACCES 13
+#define NFSERR_EXIST 17
+#define NFSERR_XDEV 18 /* Version 3 only */
+#define NFSERR_NODEV 19
+#define NFSERR_NOTDIR 20
+#define NFSERR_ISDIR 21
+#define NFSERR_INVAL 22 /* Version 3 only */
+#define NFSERR_FBIG 27
+#define NFSERR_NOSPC 28
+#define NFSERR_ROFS 30
+#define NFSERR_MLINK 31 /* Version 3 only */
+#define NFSERR_NAMETOL 63
+#define NFSERR_NOTEMPTY 66
+#define NFSERR_DQUOT 69
+#define NFSERR_STALE 70
+#define NFSERR_REMOTE 71 /* Version 3 only */
+#define NFSERR_WFLUSH 99 /* Version 2 only */
+#define NFSERR_BADHANDLE 10001 /* The rest Version 3 only */
+#define NFSERR_NOT_SYNC 10002
+#define NFSERR_BAD_COOKIE 10003
+#define NFSERR_NOTSUPP 10004
+#define NFSERR_TOOSMALL 10005
+#define NFSERR_SERVERFAULT 10006
+#define NFSERR_BADTYPE 10007
+#define NFSERR_JUKEBOX 10008
/* Sizes in bytes of various nfs rpc components */
-#define NFSX_FH 32
#define NFSX_UNSIGNED 4
-#define NFSX_NFSFATTR 68
-#define NFSX_NQFATTR 92
-#define NFSX_NFSSATTR 32
-#define NFSX_NQSATTR 44
-#define NFSX_COOKIE 4
-#define NFSX_NFSSTATFS 20
-#define NFSX_NQSTATFS 28
-#define NFSX_FATTR(isnq) ((isnq) ? NFSX_NQFATTR : NFSX_NFSFATTR)
-#define NFSX_SATTR(isnq) ((isnq) ? NFSX_NQSATTR : NFSX_NFSSATTR)
-#define NFSX_STATFS(isnq) ((isnq) ? NFSX_NQSTATFS : NFSX_NFSSTATFS)
-/* nfs rpc procedure numbers */
+/* specific to NFS Version 2 */
+#define NFSX_V2FH 32
+#define NFSX_V2FATTR 68
+#define NFSX_V2SATTR 32
+#define NFSX_V2COOKIE 4
+#define NFSX_V2STATFS 20
+
+/* specific to NFS Version 3 */
+#define NFSX_V3FH 16 /* size this server uses */
+#define NFSX_V3FHMAX 64 /* max. allowed by protocol */
+#define NFSX_V3FATTR 84
+#define NFSX_V3SATTR 60 /* max. all fields filled in */
+#define NFSX_V3COOKIEVERF 8
+
+/* variants for both versions */
+#define NFSX_FH(v3) ((v3) ? (NFSX_V3FHMAX + NFSX_UNSIGNED) : \
+ NFSX_V2FH)
+#define NFSX_SRVFH(v3) ((v3) ? NFSX_V3FH : NFSX_V2FH)
+#define NFSX_FATTR(v3) ((v3) ? NFSX_V3FATTR : NFSX_V2FATTR)
+#define NFSX_POSTOPATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : 0)
+#define NFSX_POSTOPORFATTR(v3) ((v3) ? (NFSX_V3FATTR + NFSX_UNSIGNED) : \
+ NFSX_V2FATTR)
+#define NFSX_WCCDATA(v3) ((v3) ? (NFSX_V3FATTR + 32) : 0)
+#define NFSX_WCCORFATTR(v3) ((v3) ? (NFSX_V3FATTR + 32) : NFSX_V2FATTR)
+#define NFSX_SATTR(v3) ((v3) ? NFSX_V3SATTR : NFSX_V2SATTR)
+#define NFSX_COOKIEVERF(v3) ((v3) ? NFSX_V3COOKIEVERF : 0)
+#define NFSX_STATFS(isv3) ((isv3) ? NFSX_NFSV3STATFS : NFSX_NFSSTATFS)
+
+/* nfs rpc procedure numbers (before version mapping) */
#define NFSPROC_NULL 0
#define NFSPROC_GETATTR 1
#define NFSPROC_SETATTR 2
-#define NFSPROC_NOOP 3
-#define NFSPROC_ROOT NFSPROC_NOOP /* Obsolete */
-#define NFSPROC_LOOKUP 4
+#define NFSPROC_LOOKUP 3
+#define NFSPROC_ACCESS 4
#define NFSPROC_READLINK 5
#define NFSPROC_READ 6
-#define NFSPROC_WRITECACHE NFSPROC_NOOP /* Obsolete */
-#define NFSPROC_WRITE 8
-#define NFSPROC_CREATE 9
-#define NFSPROC_REMOVE 10
-#define NFSPROC_RENAME 11
-#define NFSPROC_LINK 12
-#define NFSPROC_SYMLINK 13
-#define NFSPROC_MKDIR 14
-#define NFSPROC_RMDIR 15
+#define NFSPROC_WRITE 7
+#define NFSPROC_CREATE 8
+#define NFSPROC_MKDIR 9
+#define NFSPROC_SYMLINK 10
+#define NFSPROC_MKNOD 11
+#define NFSPROC_REMOVE 12
+#define NFSPROC_RMDIR 13
+#define NFSPROC_RENAME 14
+#define NFSPROC_LINK 15
#define NFSPROC_READDIR 16
-#define NFSPROC_STATFS 17
+#define NFSPROC_READDIRPLUS 17
+#define NFSPROC_FSSTAT 18
+#define NFSPROC_FSINFO 19
+#define NFSPROC_PATHCONF 20
+#define NFSPROC_COMMIT 21
-/* NQ nfs numbers */
-#define NQNFSPROC_READDIRLOOK 18
-#define NQNFSPROC_GETLEASE 19
-#define NQNFSPROC_VACATED 20
-#define NQNFSPROC_EVICTED 21
-#define NQNFSPROC_ACCESS 22
+/* And leasing (nqnfs) procedure numbers */
+#define NQNFSPROC_GETLEASE 22
+#define NQNFSPROC_VACATED 23
+#define NQNFSPROC_EVICTED 24
+
+#define NFS_NPROCS 25
+
+/* Actual Version 2 procedure numbers */
+#define NFSV2PROC_NULL 0
+#define NFSV2PROC_GETATTR 1
+#define NFSV2PROC_SETATTR 2
+#define NFSV2PROC_NOOP 3
+#define NFSV2PROC_ROOT NFSV2PROC_NOOP /* Obsolete */
+#define NFSV2PROC_LOOKUP 4
+#define NFSV2PROC_READLINK 5
+#define NFSV2PROC_READ 6
+#define NFSV2PROC_WRITECACHE NFSV2PROC_NOOP /* Obsolete */
+#define NFSV2PROC_WRITE 8
+#define NFSV2PROC_CREATE 9
+#define NFSV2PROC_REMOVE 10
+#define NFSV2PROC_RENAME 11
+#define NFSV2PROC_LINK 12
+#define NFSV2PROC_SYMLINK 13
+#define NFSV2PROC_MKDIR 14
+#define NFSV2PROC_RMDIR 15
+#define NFSV2PROC_READDIR 16
+#define NFSV2PROC_STATFS 17
-#define NFS_NPROCS 23
/* Conversion macros */
-#define vtonfs_mode(t,m) \
+extern int vttoif_tab[];
+#define vtonfsv2_mode(t,m) \
txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) : \
MAKEIMODE((t), (m)))
-#define nfstov_mode(a) (fxdr_unsigned(u_short, (a))&07777)
-#define vtonfs_type(a) txdr_unsigned(nfs_type[((long)(a))])
-#define nfstov_type(a) ntov_type[fxdr_unsigned(u_long,(a))&0x7]
+#define vtonfsv3_mode(m) txdr_unsigned((m) & 07777)
+#define nfstov_mode(a) (fxdr_unsigned(u_short, (a))&07777)
+#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((long)(a))])
+#define vtonfsv3_type(a) txdr_unsigned(nfsv3_type[((long)(a))])
+#define nfsv2tov_type(a) nv2tov_type[fxdr_unsigned(u_long,(a))&0x7]
+#define nfsv3tov_type(a) nv3tov_type[fxdr_unsigned(u_long,(a))&0x7]
/* File types */
-typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 } nfstype;
+typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5,
+ NFSOCK=6, NFFIFO=7 } nfstype;
/* Structs for common parts of the rpc's */
struct nfsv2_time {
- u_long nfs_sec;
- u_long nfs_usec;
+ u_long nfsv2_sec;
+ u_long nfsv2_usec;
+};
+typedef struct nfsv2_time nfstime2;
+
+struct nfsv3_time {
+ u_long nfsv3_sec;
+ u_long nfsv3_nsec;
};
+typedef struct nfsv3_time nfstime3;
-struct nqnfs_time {
- u_long nq_sec;
- u_long nq_nsec;
+/*
+ * Quads are defined as arrays of 2 longs to ensure dense packing for the
+ * protocol and to facilitate xdr conversion.
+ */
+struct nfs_uquad {
+ u_long nfsuquad[2];
};
+typedef struct nfs_uquad nfsuint64;
/*
* File attributes and setable attributes. These structures cover both
- * NFS version 2 and the NQNFS protocol. Note that the union is only
- * used to that one pointer can refer to both variants. These structures
+ * NFS version 2 and the version 3 protocol. Note that the union is only
+ * used so that one pointer can refer to both variants. These structures
* go out on the wire and must be densely packed, so no quad data types
* are used. (all fields are longs or u_longs or structures of same)
- * NB: You can't do sizeof(struct nfsv2_fattr), you must use the
- * NFSX_FATTR(isnq) macro.
+ * NB: You can't do sizeof(struct nfs_fattr), you must use the
+ * NFSX_FATTR(v3) macro.
*/
-struct nfsv2_fattr {
+struct nfs_fattr {
u_long fa_type;
u_long fa_mode;
u_long fa_nlink;
@@ -164,102 +236,85 @@ struct nfsv2_fattr {
u_long fa_gid;
union {
struct {
- u_long nfsfa_size;
- u_long nfsfa_blocksize;
- u_long nfsfa_rdev;
- u_long nfsfa_blocks;
- u_long nfsfa_fsid;
- u_long nfsfa_fileid;
- struct nfsv2_time nfsfa_atime;
- struct nfsv2_time nfsfa_mtime;
- struct nfsv2_time nfsfa_ctime;
+ u_long nfsv2fa_size;
+ u_long nfsv2fa_blocksize;
+ u_long nfsv2fa_rdev;
+ u_long nfsv2fa_blocks;
+ u_long nfsv2fa_fsid;
+ u_long nfsv2fa_fileid;
+ nfstime2 nfsv2fa_atime;
+ nfstime2 nfsv2fa_mtime;
+ nfstime2 nfsv2fa_ctime;
} fa_nfsv2;
struct {
- struct {
- u_long nqfa_qsize[2];
- } nqfa_size;
- u_long nqfa_blocksize;
- u_long nqfa_rdev;
- struct {
- u_long nqfa_qbytes[2];
- } nqfa_bytes;
- u_long nqfa_fsid;
- u_long nqfa_fileid;
- struct nqnfs_time nqfa_atime;
- struct nqnfs_time nqfa_mtime;
- struct nqnfs_time nqfa_ctime;
- u_long nqfa_flags;
- u_long nqfa_gen;
- struct {
- u_long nqfa_qfilerev[2];
- } nqfa_filerev;
- } fa_nqnfs;
+ nfsuint64 nfsv3fa_size;
+ nfsuint64 nfsv3fa_used;
+ nfsuint64 nfsv3fa_rdev;
+ nfsuint64 nfsv3fa_fsid;
+ nfsuint64 nfsv3fa_fileid;
+ nfstime3 nfsv3fa_atime;
+ nfstime3 nfsv3fa_mtime;
+ nfstime3 nfsv3fa_ctime;
+ } fa_nfsv3;
} fa_un;
};
/* and some ugly defines for accessing union components */
-#define fa_nfssize fa_un.fa_nfsv2.nfsfa_size
-#define fa_nfsblocksize fa_un.fa_nfsv2.nfsfa_blocksize
-#define fa_nfsrdev fa_un.fa_nfsv2.nfsfa_rdev
-#define fa_nfsblocks fa_un.fa_nfsv2.nfsfa_blocks
-#define fa_nfsfsid fa_un.fa_nfsv2.nfsfa_fsid
-#define fa_nfsfileid fa_un.fa_nfsv2.nfsfa_fileid
-#define fa_nfsatime fa_un.fa_nfsv2.nfsfa_atime
-#define fa_nfsmtime fa_un.fa_nfsv2.nfsfa_mtime
-#define fa_nfsctime fa_un.fa_nfsv2.nfsfa_ctime
-#define fa_nqsize fa_un.fa_nqnfs.nqfa_size
-#define fa_nqblocksize fa_un.fa_nqnfs.nqfa_blocksize
-#define fa_nqrdev fa_un.fa_nqnfs.nqfa_rdev
-#define fa_nqbytes fa_un.fa_nqnfs.nqfa_bytes
-#define fa_nqfsid fa_un.fa_nqnfs.nqfa_fsid
-#define fa_nqfileid fa_un.fa_nqnfs.nqfa_fileid
-#define fa_nqatime fa_un.fa_nqnfs.nqfa_atime
-#define fa_nqmtime fa_un.fa_nqnfs.nqfa_mtime
-#define fa_nqctime fa_un.fa_nqnfs.nqfa_ctime
-#define fa_nqflags fa_un.fa_nqnfs.nqfa_flags
-#define fa_nqgen fa_un.fa_nqnfs.nqfa_gen
-#define fa_nqfilerev fa_un.fa_nqnfs.nqfa_filerev
+#define fa2_size fa_un.fa_nfsv2.nfsv2fa_size
+#define fa2_blocksize fa_un.fa_nfsv2.nfsv2fa_blocksize
+#define fa2_rdev fa_un.fa_nfsv2.nfsv2fa_rdev
+#define fa2_blocks fa_un.fa_nfsv2.nfsv2fa_blocks
+#define fa2_fsid fa_un.fa_nfsv2.nfsv2fa_fsid
+#define fa2_fileid fa_un.fa_nfsv2.nfsv2fa_fileid
+#define fa2_atime fa_un.fa_nfsv2.nfsv2fa_atime
+#define fa2_mtime fa_un.fa_nfsv2.nfsv2fa_mtime
+#define fa2_ctime fa_un.fa_nfsv2.nfsv2fa_ctime
+#define fa3_size fa_un.fa_nfsv3.nfsv3fa_size
+#define fa3_used fa_un.fa_nfsv3.nfsv3fa_used
+#define fa3_rdev fa_un.fa_nfsv3.nfsv3fa_rdev
+#define fa3_fsid fa_un.fa_nfsv3.nfsv3fa_fsid
+#define fa3_fileid fa_un.fa_nfsv3.nfsv3fa_fileid
+#define fa3_atime fa_un.fa_nfsv3.nfsv3fa_atime
+#define fa3_mtime fa_un.fa_nfsv3.nfsv3fa_mtime
+#define fa3_ctime fa_un.fa_nfsv3.nfsv3fa_ctime
struct nfsv2_sattr {
- u_long sa_mode;
- u_long sa_uid;
- u_long sa_gid;
- union {
- struct {
- u_long nfssa_size;
- struct nfsv2_time nfssa_atime;
- struct nfsv2_time nfssa_mtime;
- } sa_nfsv2;
- struct {
- struct {
- u_long nqsa_qsize[2];
- } nqsa_size;
- struct nqnfs_time nqsa_atime;
- struct nqnfs_time nqsa_mtime;
- u_long nqsa_flags;
- u_long nqsa_rdev;
- } sa_nqnfs;
- } sa_un;
+ u_long sa_mode;
+ u_long sa_uid;
+ u_long sa_gid;
+ u_long sa_size;
+ nfstime2 sa_atime;
+ nfstime2 sa_mtime;
};
-/* and some ugly defines for accessing the unions */
-#define sa_nfssize sa_un.sa_nfsv2.nfssa_size
-#define sa_nfsatime sa_un.sa_nfsv2.nfssa_atime
-#define sa_nfsmtime sa_un.sa_nfsv2.nfssa_mtime
-#define sa_nqsize sa_un.sa_nqnfs.nqsa_size
-#define sa_nqatime sa_un.sa_nqnfs.nqsa_atime
-#define sa_nqmtime sa_un.sa_nqnfs.nqsa_mtime
-#define sa_nqflags sa_un.sa_nqnfs.nqsa_flags
-#define sa_nqrdev sa_un.sa_nqnfs.nqsa_rdev
-
struct nfsv2_statfs {
u_long sf_tsize;
u_long sf_bsize;
u_long sf_blocks;
u_long sf_bfree;
u_long sf_bavail;
- u_long sf_files; /* Nqnfs only */
- u_long sf_ffree; /* ditto */
};
+struct nfsv3_fsstat {
+ nfsuint64 sf_tbytes;
+ nfsuint64 sf_fbytes;
+ nfsuint64 sf_abytes;
+ nfsuint64 sf_tfiles;
+ nfsuint64 sf_ffiles;
+ nfsuint64 sf_afiles;
+ u_long sf_invarsec;
+};
+
+struct nfsv3_fsinfo {
+ u_long fs_rtmax;
+ u_long fs_rtpref;
+ u_long fs_rtmult;
+ u_long fs_wtmax;
+ u_long fs_wtpref;
+ u_long fs_wtmult;
+ u_long fs_dtpref;
+ nfsuint64 fs_maxfilesize;
+ nfstime3 fs_time_delta;
+ u_long fs_properties;
+};
#endif
diff --git a/sys/nfs/nqnfs.h b/sys/nfs/nqnfs.h
index 0f8f12b238dc..194bc9099a89 100644
--- a/sys/nfs/nqnfs.h
+++ b/sys/nfs/nqnfs.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nqnfs.h 8.1 (Berkeley) 6/10/93
- * $Id: nqnfs.h,v 1.5 1994/10/02 17:27:07 phk Exp $
+ * $Id: nqnfs.h,v 1.6 1994/10/17 17:47:45 phk Exp $
*/
#ifndef _NFS_NQNFS_H_
@@ -58,7 +58,7 @@
#define NQLCHSZ 256 /* Server hash table size */
#define NQNFS_PROG 300105 /* As assigned by Sun */
-#define NQNFS_VER1 1
+#define NQNFS_VER3 3
#define NQNFS_EVICTSIZ 156 /* Size of eviction request in bytes */
/*
@@ -143,14 +143,6 @@ struct nqm {
};
/*
- * Flag bits for flags argument to nqsrv_getlease.
- */
-#define NQL_READ LEASE_READ /* Read Request */
-#define NQL_WRITE LEASE_WRITE /* Write Request */
-#define NQL_CHECK 0x4 /* Check for lease */
-#define NQL_NOVAL 0xffffffff /* Invalid */
-
-/*
* Special value for slp for local server calls.
*/
#define NQLOCALSLP ((struct nfssvc_sock *) -1)
@@ -160,9 +152,9 @@ struct nqm {
*/
#define nqsrv_getl(v, l) \
(void) nqsrv_getlease((v), &nfsd->nd_duration, \
- ((nfsd->nd_nqlflag != 0 && nfsd->nd_nqlflag != NQL_NOVAL) ? nfsd->nd_nqlflag : \
- ((l) | NQL_CHECK)), \
- nfsd, nam, &cache, &frev, cred)
+ ((nfsd->nd_flag & ND_LEASE) ? (nfsd->nd_flag & ND_LEASE) : \
+ ((l) | ND_CHECK)), \
+ slp, procp, nfsd->nd_nam, &cache, &frev, cred)
/*
* Client side macros that check for a valid lease.
@@ -170,13 +162,13 @@ struct nqm {
#define NQNFS_CKINVALID(v, n, f) \
((time.tv_sec > (n)->n_expiry && \
VFSTONFS((v)->v_mount)->nm_timeouts < VFSTONFS((v)->v_mount)->nm_deadthresh) \
- || ((f) == NQL_WRITE && ((n)->n_flag & NQNFSWRITE) == 0))
+ || ((f) == ND_WRITE && ((n)->n_flag & NQNFSWRITE) == 0))
#define NQNFS_CKCACHABLE(v, f) \
((time.tv_sec <= VTONFS(v)->n_expiry || \
VFSTONFS((v)->v_mount)->nm_timeouts >= VFSTONFS((v)->v_mount)->nm_deadthresh) \
&& (VTONFS(v)->n_flag & NQNFSNONCACHE) == 0 && \
- ((f) == NQL_READ || (VTONFS(v)->n_flag & NQNFSWRITE)))
+ ((f) == ND_READ || (VTONFS(v)->n_flag & NQNFSWRITE)))
#define NQNFS_NEEDLEASE(v, p) \
(time.tv_sec > VTONFS(v)->n_expiry ? \
@@ -184,7 +176,7 @@ struct nqm {
(((time.tv_sec + NQ_RENEWAL) > VTONFS(v)->n_expiry && \
nqnfs_piggy[p]) ? \
((VTONFS(v)->n_flag & NQNFSWRITE) ? \
- NQL_WRITE : nqnfs_piggy[p]) : 0))
+ ND_WRITE : nqnfs_piggy[p]) : 0))
/*
* List head for timer queue.
@@ -204,13 +196,12 @@ u_long nqfhhash;
*/
#define NQNFS_EXPIRED 500
#define NQNFS_TRYLATER 501
-#define NQNFS_AUTHERR 502
-#ifdef KERNEL
-void nfs_lease_check __P((struct vnode *, struct proc *, struct ucred *, int));
-void nfs_lease_updatetime __P((int));
+#if defined(KERNEL) || defined(_KERNEL)
+void nqnfs_lease_check __P((struct vnode *, struct proc *, struct ucred *, int));
+void nqnfs_lease_updatetime __P((int));
int nqsrv_cmpnam __P((struct nfssvc_sock *,struct mbuf *,struct nqhost *));
-int nqsrv_getlease __P((struct vnode *,u_long *,int,struct nfsd *,struct mbuf *,int *,u_quad_t *,struct ucred *));
+int nqsrv_getlease __P((struct vnode *,u_long *,int,struct nfssvc_sock *,struct proc *,struct mbuf *,int *,u_quad_t *,struct ucred *));
int nqnfs_getlease __P((struct vnode *,int,struct ucred *,struct proc *));
int nqnfs_callback __P((struct nfsmount *,struct mbuf *,struct mbuf *,caddr_t));
int nqnfs_clientd __P((struct nfsmount *,struct ucred *,struct nfsd_cargs *,int,caddr_t,struct proc *));
diff --git a/sys/nfs/rpcv2.h b/sys/nfs/rpcv2.h
index 2360cdc3c40a..b53d5aa47dcb 100644
--- a/sys/nfs/rpcv2.h
+++ b/sys/nfs/rpcv2.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)rpcv2.h 8.1 (Berkeley) 6/10/93
- * $Id: rpcv2.h,v 1.2 1994/08/02 07:52:29 davidg Exp $
+ * $Id: rpcv2.h,v 1.3 1994/08/21 06:50:15 paul Exp $
*/
#ifndef _NFS_RPCV2_H_
@@ -52,10 +52,18 @@
#define RPCAUTH_NULL 0
#define RPCAUTH_UNIX 1
#define RPCAUTH_SHORT 2
+#define RPCAUTH_KERB4 4
#define RPCAUTH_NQNFS 300000
#define RPCAUTH_MAXSIZ 400
+#define RPCVERF_MAXSIZ 12 /* For Kerb, can actually be 400 */
#define RPCAUTH_UNIXGIDS 16
+/*
+ * Constants associated with authentication flavours.
+ */
+#define RPCAKN_FULLNAME 0
+#define RPCAKN_NICKNAME 1
+
/* Rpc Constants */
#define RPC_CALL 0
#define RPC_REPLY 1
@@ -91,4 +99,43 @@
#define RPCMNT_PATHLEN 1024
#define RPCPROG_NFS 100003
+/*
+ * Structures used for RPCAUTH_KERB4.
+ */
+struct nfsrpc_fullverf {
+ u_long t1;
+ u_long t2;
+ u_long w2;
+};
+
+struct nfsrpc_fullblock {
+ u_long t1;
+ u_long t2;
+ u_long w1;
+ u_long w2;
+};
+
+struct nfsrpc_nickverf {
+ u_long kind;
+ struct nfsrpc_fullverf verf;
+};
+
+/*
+ * and their sizes in bytes.. If sizeof (struct nfsrpc_xx) != these
+ * constants, well then things will break in mount_nfs and nfsd.
+ */
+#define RPCX_FULLVERF 12
+#define RPCX_FULLBLOCK 16
+#define RPCX_NICKVERF 16
+
+#ifdef NFSKERB
+XXX
+#else
+typedef u_char NFSKERBKEY_T[2];
+typedef u_char NFSKERBKEYSCHED_T[2];
+#endif
+#define NFS_KERBSRV "rcmd" /* Kerberos Service for NFS */
+#define NFS_KERBTTL (30 * 60) /* Credential ttl (sec) */
+#define NFS_KERBCLOCKSKEW (5 * 60) /* Clock skew (sec) */
+#define NFS_KERBW1(t) (*((u_long *)(&((t).dat[((t).length + 3) & ~0x3]))))
#endif
diff --git a/sys/nfs/xdr_subs.h b/sys/nfs/xdr_subs.h
index ac00385e7da0..e8c363668d79 100644
--- a/sys/nfs/xdr_subs.h
+++ b/sys/nfs/xdr_subs.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)xdr_subs.h 8.1 (Berkeley) 6/10/93
- * $Id: xdr_subs.h,v 1.3 1994/08/21 06:50:16 paul Exp $
+ * $Id: xdr_subs.h,v 1.4 1995/01/10 13:11:42 davidg Exp $
*/
#ifndef _NFS_XDR_SUBS_H_
@@ -54,28 +54,28 @@
#define fxdr_unsigned(t, v) ((t)ntohl((long)(v)))
#define txdr_unsigned(v) (htonl((long)(v)))
-#define fxdr_nfstime(f, t) { \
- (t)->ts_sec = ntohl(((struct nfsv2_time *)(f))->nfs_sec); \
- if (((struct nfsv2_time *)(f))->nfs_usec != 0xffffffff) \
- (t)->ts_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfs_usec); \
+#define fxdr_nfsv2time(f, t) { \
+ (t)->ts_sec = ntohl(((struct nfsv2_time *)(f))->nfsv2_sec); \
+ if (((struct nfsv2_time *)(f))->nfsv2_usec != 0xffffffff) \
+ (t)->ts_nsec = 1000 * ntohl(((struct nfsv2_time *)(f))->nfsv2_usec); \
else \
- (t)->ts_nsec = -1; \
+ (t)->ts_nsec = 0; \
}
-#define txdr_nfstime(f, t) { \
- ((struct nfsv2_time *)(t))->nfs_sec = htonl((f)->ts_sec); \
+#define txdr_nfsv2time(f, t) { \
+ ((struct nfsv2_time *)(t))->nfsv2_sec = htonl((f)->ts_sec); \
if ((f)->ts_nsec != -1) \
- ((struct nfsv2_time *)(t))->nfs_usec = htonl((f)->ts_nsec / 1000); \
+ ((struct nfsv2_time *)(t))->nfsv2_usec = htonl((f)->ts_nsec / 1000); \
else \
- ((struct nfsv2_time *)(t))->nfs_usec = 0xffffffff; \
+ ((struct nfsv2_time *)(t))->nfsv2_usec = 0xffffffff; \
}
-#define fxdr_nqtime(f, t) { \
- (t)->ts_sec = ntohl(((struct nqnfs_time *)(f))->nq_sec); \
- (t)->ts_nsec = ntohl(((struct nqnfs_time *)(f))->nq_nsec); \
+#define fxdr_nfsv3time(f, t) { \
+ (t)->ts_sec = ntohl(((struct nfsv3_time *)(f))->nfsv3_sec); \
+ (t)->ts_nsec = ntohl(((struct nfsv3_time *)(f))->nfsv3_nsec); \
}
-#define txdr_nqtime(f, t) { \
- ((struct nqnfs_time *)(t))->nq_sec = htonl((f)->ts_sec); \
- ((struct nqnfs_time *)(t))->nq_nsec = htonl((f)->ts_nsec); \
+#define txdr_nfsv3time(f, t) { \
+ ((struct nfsv3_time *)(t))->nfsv3_sec = htonl((f)->ts_sec); \
+ ((struct nfsv3_time *)(t))->nfsv3_nsec = htonl((f)->ts_nsec); \
}
#define fxdr_hyper(f, t) { \
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h
index cbf80c6d7fd6..e1a0f07a71ef 100644
--- a/sys/nfsclient/nfs.h
+++ b/sys/nfsclient/nfs.h
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs.h 8.1 (Berkeley) 6/10/93
- * $Id: nfs.h,v 1.8 1994/11/02 00:11:00 wollman Exp $
+ * $Id: nfs.h,v 1.9 1995/02/14 06:22:18 phk Exp $
*/
#ifndef _NFS_NFS_H_
@@ -45,11 +45,12 @@
*/
#define NFS_MAXIOVEC 34
-#define NFS_HZ 25 /* Ticks per second for NFS timeouts */
-#define NFS_TIMEO (1*NFS_HZ) /* Default timeout = 1 second */
-#define NFS_MINTIMEO (1*NFS_HZ) /* Min timeout to use */
-#define NFS_MAXTIMEO (60*NFS_HZ) /* Max timeout to backoff to */
-#define NFS_MINIDEMTIMEO (5*NFS_HZ) /* Min timeout for non-idempotent ops*/
+#define NFS_TICKINTVL 5 /* Desired time for a tick (msec) */
+#define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */
+#define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */
+#define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */
+#define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */
+#define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/
#define NFS_MAXREXMIT 100 /* Stop counting after this many */
#define NFS_MAXWINDOW 1024 /* Max number of outstanding requests */
#define NFS_RETRANS 10 /* Num of retrans for soft mounts */
@@ -62,13 +63,81 @@
#endif
#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */
#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */
+#define NFS_READDIRSIZE 8192 /* Def. readdir size */
#define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */
#define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */
-#define NFS_MAXREADDIR NFS_MAXDATA /* Max. size of directory read */
#define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */
-#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */
-#define NFS_DIRBLKSIZ 1024 /* Size of an NFS directory block */
+#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */
+#define NFS_MAXGATHERDELAY 100 /* Max. write gather delay (msec) */
+#ifndef NFS_GATHERDELAY
+#define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */
+#endif
+#define NFS_DIRBLKSIZ 4096 /* Must be a multiple of DIRBLKSIZ */
+
+/*
+ * Oddballs
+ */
#define NMOD(a) ((a) % nfs_asyncdaemons)
+#define NFS_CMPFH(n, f, s) \
+ ((n)->n_fhsize == (s) && !bcmp((caddr_t)(n)->n_fhp, (caddr_t)(f), (s)))
+#define NFS_ISV3(v) (VFSTONFS((v)->v_mount)->nm_flag & NFSMNT_NFSV3)
+#define NFS_SRVMAXDATA(n) \
+ (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \
+ NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA)
+
+/*
+ * XXX
+ * sys/buf.h should be editted to change B_APPENDWRITE --> B_NEEDCOMMIT, but
+ * until then...
+ * Same goes for sys/malloc.h, which needs M_NFSDIROFF,
+ * M_NFSRVDESC and M_NFSBIGFH added.
+ * The VA_EXCLUSIVE flag should be added for va_vaflags and set for an
+ * exclusive create.
+ * The B_INVAFTERWRITE flag should be set to whatever is required by the
+ * buffer cache code to say "Invalidate the block after it is written back".
+ */
+#ifndef B_NEEDCOMMIT
+#define B_NEEDCOMMIT B_APPENDWRITE
+#endif
+#ifndef M_NFSRVDESC
+#define M_NFSRVDESC M_TEMP
+#endif
+#ifndef M_NFSDIROFF
+#define M_NFSDIROFF M_TEMP
+#endif
+#ifndef M_NFSBIGFH
+#define M_NFSBIGFH M_TEMP
+#endif
+#ifndef VA_EXCLUSIVE
+#define VA_EXCLUSIVE 0
+#endif
+#ifdef __FreeBSD__
+#define B_INVAFTERWRITE B_NOCACHE
+#else
+#define B_INVAFTERWRITE B_INVAL
+#endif
+
+/*
+ * These ifdefs try to handle the differences between the various 4.4BSD-Lite
+ * based vfs interfaces.
+ * btw: NetBSD-current does have a VOP_LEASDE(), but I don't know how to
+ * differentiate between NetBSD-1.0 and NetBSD-current, so..
+ * I also don't know about BSDi's 2.0 release.
+ */
+#if !defined(HAS_VOPLEASE) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+#define HAS_VOPLEASE 1
+#endif
+#if !defined(HAS_VOPREVOKE) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+#define HAS_VOPREVOKE 1
+#endif
+
+/*
+ * The IO_METASYNC flag should be implemented for local file systems.
+ * (Until then, it is nothin at all.)
+ */
+#ifndef IO_METASYNC
+#define IO_METASYNC 0
+#endif
/*
* Set the attribute timeout based on how recently the file has been modified.
@@ -80,6 +149,20 @@
(time.tv_sec - (np)->n_mtime) / 10))
/*
+ * Expected allocation sizes for major data structures. If the actual size
+ * of the structure exceeds these sizes, then malloc() will be allocating
+ * almost twice the memory required. This is used in nfs_init() to warn
+ * the sysadmin that the size of a structure should be reduced.
+ * (These sizes are always a power of 2. If the kernel malloc() changes
+ * to one that does not allocate space in powers of 2 size, then this all
+ * becomes bunk!)
+ */
+#define NFS_NODEALLOC 256
+#define NFS_MNTALLOC 512
+#define NFS_SVCALLOC 256
+#define NFS_UIDALLOC 128
+
+/*
* Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs
* should ever try and use it.
*/
@@ -95,7 +178,12 @@ struct nfsd_srvargs {
u_long nsd_haddr; /* Ip address of client */
struct ucred nsd_cr; /* Cred. uid maps to */
int nsd_authlen; /* Length of auth string (ret) */
- char *nsd_authstr; /* Auth string (ret) */
+ u_char *nsd_authstr; /* Auth string (ret) */
+ int nsd_verflen; /* and the verfier */
+ u_char *nsd_verfstr;
+ struct timeval nsd_timestamp; /* timestamp from verifier */
+ u_long nsd_ttl; /* credential ttl (sec) */
+ NFSKERBKEY_T nsd_key; /* Session key */
};
struct nfsd_cargs {
@@ -103,7 +191,10 @@ struct nfsd_cargs {
uid_t ncd_authuid; /* Effective uid */
int ncd_authtype; /* Type of authenticator */
int ncd_authlen; /* Length of authenticator string */
- char *ncd_authstr; /* Authenticator string */
+ u_char *ncd_authstr; /* Authenticator string */
+ int ncd_verflen; /* and the verifier */
+ u_char *ncd_verfstr;
+ NFSKERBKEY_T ncd_key; /* Session key */
};
/*
@@ -142,6 +233,7 @@ struct nfsstats {
int srvnqnfs_leases;
int srvnqnfs_maxleases;
int srvnqnfs_getleases;
+ int srvvop_writes;
};
/*
@@ -173,7 +265,7 @@ struct nfsstats {
* such as SIGALRM will not expect file I/O system calls to be interrupted
* by them and break.
*/
-#ifdef KERNEL
+#if defined(KERNEL) || defined(_KERNEL)
struct uio; struct buf; struct vattr; struct nameidata; /* XXX */
@@ -224,17 +316,29 @@ TAILQ_HEAD(, nfsreq) nfs_reqq;
#define R_MUSTRESEND 0x40 /* Must resend request */
#define R_GETONEREP 0x80 /* Probe for one reply only */
-extern struct nfsstats nfsstats;
-
/*
* A list of nfssvc_sock structures is maintained with all the sockets
* that require service by the nfsd.
* The nfsuid structs hang off of the nfssvc_sock structs in both lru
* and uid hash lists.
*/
-#define NUIDHASHSIZ 32
+#ifndef NFS_UIDHASHSIZ
+#define NFS_UIDHASHSIZ 29 /* Tune the size of nfssvc_sock with this */
+#endif
#define NUIDHASH(sock, uid) \
- (&(sock)->ns_uidhashtbl[(uid) & (sock)->ns_uidhash])
+ (&(sock)->ns_uidhashtbl[(uid) % NFS_UIDHASHSIZ])
+#ifndef NFS_WDELAYHASHSIZ
+#define NFS_WDELAYHASHSIZ 16 /* and with this */
+#endif
+#define NWDELAYHASH(sock, f) \
+ (&(sock)->ns_wdelayhashtbl[(*((u_long *)(f))) % NFS_WDELAYHASHSIZ])
+#ifndef NFS_MUIDHASHSIZ
+#define NFS_MUIDHASHSIZ 67 /* Tune the size of nfsmount with this */
+#endif
+#define NMUIDHASH(nmp, uid) \
+ (&(nmp)->nm_uidhashtbl[(uid) % NFS_MUIDHASHSIZ])
+#define NFSNOHASH(fhsum) \
+ (&nfsnodehashtbl[(fhsum) & nfsnodehash])
/*
* Network address hash list element
@@ -248,35 +352,41 @@ struct nfsuid {
TAILQ_ENTRY(nfsuid) nu_lru; /* LRU chain */
LIST_ENTRY(nfsuid) nu_hash; /* Hash list */
int nu_flag; /* Flags */
- uid_t nu_uid; /* Uid mapped by this entry */
union nethostaddr nu_haddr; /* Host addr. for dgram sockets */
struct ucred nu_cr; /* Cred uid mapped to */
+ int nu_expire; /* Expiry time (sec) */
+ struct timeval nu_timestamp; /* Kerb. timestamp */
+ u_long nu_nickname; /* Nickname on server */
+ NFSKERBKEY_T nu_key; /* and session key */
};
#define nu_inetaddr nu_haddr.had_inetaddr
#define nu_nam nu_haddr.had_nam
/* Bits for nu_flag */
#define NU_INETADDR 0x1
+#define NU_NAM 0x2
+#define NU_NETFAM(u) (((u)->nu_flag & NU_INETADDR) ? AF_INET : AF_ISO)
struct nfssvc_sock {
TAILQ_ENTRY(nfssvc_sock) ns_chain; /* List of all nfssvc_sock's */
TAILQ_HEAD(, nfsuid) ns_uidlruhead;
- LIST_HEAD(, nfsuid) *ns_uidhashtbl;
- u_long ns_uidhash;
-
- int ns_flag;
- u_long ns_sref;
struct file *ns_fp;
struct socket *ns_so;
- int ns_solock;
struct mbuf *ns_nam;
- int ns_cc;
struct mbuf *ns_raw;
struct mbuf *ns_rawend;
- int ns_reclen;
struct mbuf *ns_rec;
struct mbuf *ns_recend;
+ struct mbuf *ns_frag;
+ int ns_flag;
+ int ns_solock;
+ int ns_cc;
+ int ns_reclen;
int ns_numuids;
+ u_long ns_sref;
+ LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */
+ LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ];
+ LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ];
};
/* Bits for "ns_flag" */
@@ -285,6 +395,7 @@ struct nfssvc_sock {
#define SLP_NEEDQ 0x04
#define SLP_DISCONN 0x08
#define SLP_GETSTREAM 0x10
+#define SLP_LASTFRAG 0x20
#define SLP_ALLFLAGS 0xff
TAILQ_HEAD(, nfssvc_sock) nfssvc_sockhead;
@@ -296,73 +407,124 @@ int nfssvc_sockhead_flag;
* One of these structures is allocated for each nfsd.
*/
struct nfsd {
- TAILQ_ENTRY(nfsd) nd_chain; /* List of all nfsd's */
- int nd_flag; /* NFSD_ flags */
- struct nfssvc_sock *nd_slp; /* Current socket */
- struct mbuf *nd_nam; /* Client addr for datagram req. */
- struct mbuf *nd_mrep; /* Req. mbuf list */
- struct mbuf *nd_md;
- caddr_t nd_dpos; /* Position in list */
- int nd_procnum; /* RPC procedure number */
- u_long nd_retxid; /* RPC xid */
- int nd_repstat; /* Reply status value */
- struct ucred nd_cr; /* Credentials for req. */
- int nd_nqlflag; /* Leasing flag */
- u_long nd_duration; /* Lease duration */
- int nd_authlen; /* Authenticator len */
- u_char nd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */
- struct proc *nd_procp; /* Proc ptr */
+ TAILQ_ENTRY(nfsd) nfsd_chain; /* List of all nfsd's */
+ int nfsd_flag; /* NFSD_ flags */
+ struct nfssvc_sock *nfsd_slp; /* Current socket */
+ int nfsd_authlen; /* Authenticator len */
+ u_char nfsd_authstr[RPCAUTH_MAXSIZ]; /* Authenticator data */
+ int nfsd_verflen; /* and the Verifier */
+ u_char nfsd_verfstr[RPCVERF_MAXSIZ];
+ struct proc *nfsd_procp; /* Proc ptr */
+ struct nfsrv_descript *nfsd_nd; /* Associated nfsrv_descript */
};
-/* Bits for "nd_flag" */
+/* Bits for "nfsd_flag" */
#define NFSD_WAITING 0x01
#define NFSD_REQINPROG 0x02
#define NFSD_NEEDAUTH 0x04
#define NFSD_AUTHFAIL 0x08
+/*
+ * This structure is used by the server for describing each request.
+ * Some fields are used only when write request gathering is performed.
+ */
+struct nfsrv_descript {
+ u_quad_t nd_time; /* Write deadline (usec) */
+ off_t nd_off; /* Start byte offset */
+ off_t nd_eoff; /* and end byte offset */
+ LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */
+ LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */
+ LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */
+ struct mbuf *nd_mrep; /* Request mbuf list */
+ struct mbuf *nd_md; /* Current dissect mbuf */
+ struct mbuf *nd_mreq; /* Reply mbuf list */
+ struct mbuf *nd_nam; /* and socket addr */
+ struct mbuf *nd_nam2; /* return socket addr */
+ caddr_t nd_dpos; /* Current dissect pos */
+ int nd_procnum; /* RPC # */
+ int nd_stable; /* storage type */
+ int nd_flag; /* nd_flag */
+ int nd_len; /* Length of this write */
+ int nd_repstat; /* Reply status */
+ u_long nd_retxid; /* Reply xid */
+ u_long nd_duration; /* Lease duration */
+ struct timeval nd_starttime; /* Time RPC initiated */
+ fhandle_t nd_fh; /* File handle */
+ struct ucred nd_cr; /* Credentials */
+};
+
+/* Bits for "nd_flag" */
+#define ND_READ LEASE_READ
+#define ND_WRITE LEASE_WRITE
+#define ND_CHECK 0x04
+#define ND_LEASE (ND_READ | ND_WRITE | ND_CHECK)
+#define ND_NFSV3 0x08
+#define ND_NQNFS 0x10
+#define ND_KERBNICK 0x20
+#define ND_KERBFULL 0x40
+#define ND_KERBAUTH (ND_KERBNICK | ND_KERBFULL)
+
TAILQ_HEAD(, nfsd) nfsd_head;
int nfsd_head_flag;
#define NFSD_CHECKSLP 0x01
+/*
+ * These macros compare nfsrv_descript structures.
+ */
+#define NFSW_CONTIG(o, n) \
+ ((o)->nd_eoff >= (n)->nd_off && \
+ !bcmp((caddr_t)&(o)->nd_fh, (caddr_t)&(n)->nd_fh, NFSX_V3FH))
+
+#define NFSW_SAMECRED(o, n) \
+ (((o)->nd_flag & ND_KERBAUTH) == ((n)->nd_flag & ND_KERBAUTH) && \
+ !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \
+ sizeof (struct ucred)))
+
int nfs_reply __P((struct nfsreq *));
-int nfs_getreq __P((struct nfsd *,int));
+int nfs_getreq __P((struct nfsrv_descript *,struct nfsd *,int));
int nfs_send __P((struct socket *,struct mbuf *,struct mbuf *,struct nfsreq *));
-int nfs_rephead __P((int,struct nfsd *,int,int,u_quad_t *,struct mbuf **,struct mbuf **,caddr_t *));
+int nfs_rephead __P((int,struct nfsrv_descript *,struct nfssvc_sock *,int,int,u_quad_t *,struct mbuf **,struct mbuf **,caddr_t *));
int nfs_sndlock __P((int *,struct nfsreq *));
int nfs_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *));
int nfs_vinvalbuf __P((struct vnode *,int,struct ucred *,struct proc *,int));
int nfs_readrpc __P((struct vnode *,struct uio *,struct ucred *));
-int nfs_writerpc __P((struct vnode *,struct uio *,struct ucred *,int));
+int nfs_writerpc __P((struct vnode *,struct uio *,struct ucred *,int *,int *));
int nfs_readdirrpc __P((register struct vnode *,struct uio *,struct ucred *));
+int nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct proc *));
int nfs_asyncio __P((struct buf *,struct ucred *));
int nfs_doio __P((struct buf *,struct ucred *,struct proc *));
int nfs_readlinkrpc __P((struct vnode *,struct uio *,struct ucred *));
int nfs_sigintr __P((struct nfsmount *,struct nfsreq *r,struct proc *));
-int nfs_readdirlookrpc __P((struct vnode *,register struct uio *,struct ucred *));
+int nfs_readdirplusrpc __P((struct vnode *,register struct uio *,struct ucred *));
int nfsm_disct __P((struct mbuf **,caddr_t *,int,int,caddr_t *));
-int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **,struct ucred *,struct nfssvc_sock *,struct mbuf *,int *));
+void nfsm_srvfattr __P((struct nfsrv_descript *,struct vattr *,struct nfs_fattr *));
+void nfsm_srvwcc __P((struct nfsrv_descript *,int,struct vattr *,int,struct vattr *,struct mbuf **,char **));
+void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct mbuf **,char **));
+int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **,struct ucred *,struct nfssvc_sock *,struct mbuf *,int *,int));
int nfsrv_access __P((struct vnode *,int,struct ucred *,int,struct proc *));
int netaddr_match __P((int,union nethostaddr *,struct mbuf *));
int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *));
int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *));
-int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct proc *));
+int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int));
void nfsm_adj __P((struct mbuf *,int,int));
int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *));
void nfsrv_initcache __P((void));
int nfs_rcvlock __P((struct nfsreq *));
-int nfs_getauth __P((struct nfsmount *,struct nfsreq *,struct ucred *,int *,char **,int *));
+int nfs_getauth __P((struct nfsmount *,struct nfsreq *,struct ucred *,char **,int *,char *,int *,NFSKERBKEY_T));
+int nfs_getnickauth __P((struct nfsmount *,struct ucred *,char **,int *,char *,int));
+int nfs_savenickauth __P((struct nfsmount *,struct ucred *,int,NFSKERBKEY_T,struct mbuf **,char **,struct mbuf *));
int nfs_msg __P((struct proc *,char *,char *));
int nfs_adv __P((struct mbuf **,caddr_t *,int,int));
int nfsrv_getstream __P((struct nfssvc_sock *,int));
void nfs_nhinit __P((void));
void nfs_timer __P((void*));
-struct nfsnodehashhead * nfs_hash __P((nfsv2fh_t *));
+u_long nfs_hash __P((nfsfh_t *,int));
int nfssvc_iod __P((struct proc *));
int nfssvc_nfsd __P((struct nfsd_srvargs *,caddr_t,struct proc *));
int nfssvc_addsock __P((struct file *,struct mbuf *));
-int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *));
-int nfsrv_getcache __P((struct mbuf *,struct nfsd *,struct mbuf **));
-void nfsrv_updatecache __P((struct mbuf *,struct nfsd *,int,struct mbuf *));
+int nfsrv_dorec __P((struct nfssvc_sock *,struct nfsd *,struct nfsrv_descript **));
+int nfsrv_getcache __P((struct nfsrv_descript *,struct nfssvc_sock *,struct mbuf **));
+void nfsrv_updatecache __P((struct nfsrv_descript *,int,struct mbuf *));
int mountnfs __P((struct nfs_args *,struct mount *,struct mbuf *,char *,char *,struct vnode **));
int nfs_connect __P((struct nfsmount *,struct nfsreq *));
int nfs_getattrcache __P((struct vnode *,struct vattr *));
@@ -370,9 +532,20 @@ int nfsm_strtmbuf __P((struct mbuf **,char **,char *,long));
int nfs_bioread __P((struct vnode *,struct uio *,int,struct ucred *));
int nfsm_uiotombuf __P((struct uio *,struct mbuf **,int,caddr_t *));
void nfsrv_init __P((int));
+void nfs_clearcommit __P((struct mount *));
+int nfsrv_errmap __P((struct nfsrv_descript *, int));
+void nfsrvw_coalesce __P((struct nfsrv_descript *,struct nfsrv_descript *));
+void nfsrvw_sort __P((gid_t [],int));
+void nfsrv_setcred __P((struct ucred *,struct ucred *));
+int nfs_flush __P((struct vnode *,struct ucred *,int,struct proc *,int));
+int nfs_writebp __P((struct buf *,int));
int nfsrv_vput __P(( struct vnode * ));
int nfsrv_vrele __P(( struct vnode * ));
int nfsrv_vmio __P(( struct vnode * ));
+int nfsrv_writegather __P((struct nfsrv_descript **, struct nfssvc_sock *,
+ struct proc *, struct mbuf **));
+int nfs_fsinfo __P((struct nfsmount *, struct vnode *, struct ucred *,
+ struct proc *p));
#endif /* KERNEL */
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index f92901262000..f9ae8b6fd00f 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94
- * $Id: nfs_bio.c,v 1.13 1995/05/21 21:39:21 davidg Exp $
+ * $Id: nfs_bio.c,v 1.14 1995/05/30 08:12:35 rgrimes Exp $
*/
#include <sys/param.h>
@@ -49,16 +49,30 @@
#include <vm/vm.h>
-#include <nfs/nfsnode.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsmount.h>
#include <nfs/nqnfs.h>
+#include <nfs/nfsnode.h>
struct buf *nfs_getcacheblk();
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern int nfs_numasync;
+extern struct nfsstats nfsstats;
+
+/*
+ * Ifdefs for FreeBSD-current's merged VM/buffer cache. It is unfortunate
+ * that this isn't done inside getblk() and brelse() so these calls
+ * wouldn't need to be here.
+ */
+#ifdef B_VMIO
+#define vnode_pager_uncache(vp)
+#else
+#define vfs_busy_pages(bp, f)
+#define vfs_unbusy_pages(bp)
+#define vfs_dirty_pages(bp)
+#endif
/*
* Vnode op for read using bio
@@ -72,29 +86,28 @@ nfs_bioread(vp, uio, ioflag, cred)
struct ucred *cred;
{
register struct nfsnode *np = VTONFS(vp);
- register int biosize, diff;
+ register int biosize, diff, i;
struct buf *bp = 0, *rabp;
struct vattr vattr;
struct proc *p;
- struct nfsmount *nmp;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
daddr_t lbn, rabn;
int bufsize;
int nra, error = 0, n = 0, on = 0, not_readin;
+ nfsquad_t tquad;
-#ifdef lint
- ioflag = ioflag;
-#endif /* lint */
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ)
panic("nfs_read mode");
#endif
if (uio->uio_resid == 0)
return (0);
- if (uio->uio_offset < 0 && vp->v_type != VDIR)
+ if (uio->uio_offset < 0)
return (EINVAL);
- nmp = VFSTONFS(vp->v_mount);
- biosize = NFS_MAXDGRAMDATA;
p = uio->uio_procp;
+ if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
+ (void)nfs_fsinfo(nmp, vp, cred, p);
+ biosize = nmp->nm_rsize;
/*
* For nfs, cache consistency can only be maintained approximately.
* Although RFC1094 does not specify the criteria, the following is
@@ -107,8 +120,6 @@ nfs_bioread(vp, uio, ioflag, cred)
* server, so flush all of the file's data out of the cache.
* Then force a getattr rpc to ensure that you have up to date
* attributes.
- * The mount flag NFSMNT_MYWRITE says "Assume that my writes are
- * the ones changing the modify time.
* NB: This implies that cache data can be read when up to
* NFS_ATTRTIMEO seconds out of date. If you find that you need current
* attributes this could be forced by setting n_attrstamp to 0 before
@@ -116,14 +127,15 @@ nfs_bioread(vp, uio, ioflag, cred)
*/
if ((nmp->nm_flag & NFSMNT_NQNFS) == 0 && vp->v_type != VLNK) {
if (np->n_flag & NMODIFIED) {
- if ((nmp->nm_flag & NFSMNT_MYWRITE) == 0 ||
- vp->v_type != VREG) {
+ if (vp->v_type != VREG) {
+ if (vp->v_type != VDIR)
+ panic("nfs: bioread, not dir");
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
}
np->n_attrstamp = 0;
- np->n_direofoffset = 0;
error = VOP_GETATTR(vp, &vattr, cred, p);
if (error)
return (error);
@@ -133,7 +145,8 @@ nfs_bioread(vp, uio, ioflag, cred)
if (error)
return (error);
if (np->n_mtime != vattr.va_mtime.ts_sec) {
- np->n_direofoffset = 0;
+ if (vp->v_type == VDIR)
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@@ -147,27 +160,24 @@ nfs_bioread(vp, uio, ioflag, cred)
* Get a valid lease. If cached data is stale, flush it.
*/
if (nmp->nm_flag & NFSMNT_NQNFS) {
- if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
+ if (NQNFS_CKINVALID(vp, np, ND_READ)) {
do {
- error = nqnfs_getlease(vp, NQL_READ, cred, p);
+ error = nqnfs_getlease(vp, ND_READ, cred, p);
} while (error == NQNFS_EXPIRED);
if (error)
return (error);
if (np->n_lrev != np->n_brev ||
(np->n_flag & NQNFSNONCACHE) ||
((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
- if (vp->v_type == VDIR) {
- np->n_direofoffset = 0;
- cache_purge(vp);
- }
+ if (vp->v_type == VDIR)
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
np->n_brev = np->n_lrev;
}
} else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) {
- np->n_direofoffset = 0;
- cache_purge(vp);
+ nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@@ -176,33 +186,27 @@ nfs_bioread(vp, uio, ioflag, cred)
if (np->n_flag & NQNFSNONCACHE) {
switch (vp->v_type) {
case VREG:
- error = nfs_readrpc(vp, uio, cred);
- break;
+ return (nfs_readrpc(vp, uio, cred));
case VLNK:
- error = nfs_readlinkrpc(vp, uio, cred);
- break;
+ return (nfs_readlinkrpc(vp, uio, cred));
case VDIR:
- error = nfs_readdirrpc(vp, uio, cred);
break;
default:
printf(" NQNFSNONCACHE: type %x unexpected\n",
vp->v_type);
- break;
};
- return (error);
}
switch (vp->v_type) {
case VREG:
nfsstats.biocache_reads++;
lbn = uio->uio_offset / biosize;
- on = uio->uio_offset & (biosize-1);
+ on = uio->uio_offset & (biosize - 1);
not_readin = 1;
/*
* Start the read ahead(s), as required.
*/
- if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
- lbn == vp->v_lastr + 1) {
+ if (nfs_numasync > 0 && nmp->nm_readahead > 0) {
for (nra = 0; nra < nmp->nm_readahead &&
(lbn + 1 + nra) * biosize < np->n_size; nra++) {
rabn = lbn + 1 + nra;
@@ -296,32 +300,55 @@ again:
break;
case VDIR:
nfsstats.biocache_readdirs++;
- lbn = (daddr_t)uio->uio_offset;
+ lbn = uio->uio_offset / NFS_DIRBLKSIZ;
+ on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, p);
if (!bp)
- return (EINTR);
-
+ return (EINTR);
if ((bp->b_flags & B_CACHE) == 0) {
- bp->b_flags |= B_READ;
- vfs_busy_pages(bp, 0);
- error = nfs_doio(bp, cred, p);
- if (error) {
- bp->b_flags |= B_ERROR;
- brelse(bp);
- return (error);
+ bp->b_flags |= B_READ;
+ vfs_busy_pages(bp, 0);
+ error = nfs_doio(bp, cred, p);
+ if (error) {
+ brelse(