1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94
|
1997-09-21 04:24:27 +00:00
|
|
|
* $Id: nfs_subs.c,v 1.42 1997/09/10 19:52:26 phk Exp $
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These functions support the macros and help fiddle mbuf chains for
|
|
|
|
* the nfs op functions. They do things like create the rpc header and
|
|
|
|
* copy data between mbuf chains and uio lists.
|
|
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/namei.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
1995-06-27 11:07:30 +00:00
|
|
|
#include <sys/malloc.h>
|
1997-07-16 09:06:30 +00:00
|
|
|
#include <sys/dirent.h>
|
1994-09-22 22:10:49 +00:00
|
|
|
#ifdef VFS_LKM
|
|
|
|
#include <sys/sysent.h>
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1994-10-02 17:27:07 +00:00
|
|
|
#include <vm/vm.h>
|
1995-12-07 12:48:31 +00:00
|
|
|
#include <vm/vm_param.h>
|
|
|
|
#include <vm/vm_object.h>
|
|
|
|
#include <vm/vm_extern.h>
|
NOTE: libkvm, w, ps, 'top', and any other utility which depends on struct
proc or any VM system structure will have to be rebuilt!!!
Much needed overhaul of the VM system. Included in this first round of
changes:
1) Improved pager interfaces: init, alloc, dealloc, getpages, putpages,
haspage, and sync operations are supported. The haspage interface now
provides information about clusterability. All pager routines now take
struct vm_object's instead of "pagers".
2) Improved data structures. In the previous paradigm, there is constant
confusion caused by pagers being both a data structure ("allocate a
pager") and a collection of routines. The idea of a pager structure has
escentially been eliminated. Objects now have types, and this type is
used to index the appropriate pager. In most cases, items in the pager
structure were duplicated in the object data structure and thus were
unnecessary. In the few cases that remained, a un_pager structure union
was created in the object to contain these items.
3) Because of the cleanup of #1 & #2, a lot of unnecessary layering can now
be removed. For instance, vm_object_enter(), vm_object_lookup(),
vm_object_remove(), and the associated object hash list were some of the
things that were removed.
4) simple_lock's removed. Discussion with several people reveals that the
SMP locking primitives used in the VM system aren't likely the mechanism
that we'll be adopting. Even if it were, the locking that was in the code
was very inadequate and would have to be mostly re-done anyway. The
locking in a uni-processor kernel was a no-op but went a long way toward
making the code difficult to read and debug.
5) Places that attempted to kludge-up the fact that we don't have kernel
thread support have been fixed to reflect the reality that we are really
dealing with processes, not threads. The VM system didn't have complete
thread support, so the comments and mis-named routines were just wrong.
We now use tsleep and wakeup directly in the lock routines, for instance.
6) Where appropriate, the pagers have been improved, especially in the
pager_alloc routines. Most of the pager_allocs have been rewritten and
are now faster and easier to maintain.
7) The pagedaemon pageout clustering algorithm has been rewritten and
now tries harder to output an even number of pages before and after
the requested page. This is sort of the reverse of the ideal pagein
algorithm and should provide better overall performance.
8) Unnecessary (incorrect) casts to caddr_t in calls to tsleep & wakeup
have been removed. Some other unnecessary casts have also been removed.
9) Some almost useless debugging code removed.
10) Terminology of shadow objects vs. backing objects straightened out.
The fact that the vm_object data structure escentially had this
backwards really confused things. The use of "shadow" and "backing
object" throughout the code is now internally consistent and correct
in the Mach terminology.
11) Several minor bug fixes, including one in the vm daemon that caused
0 RSS objects to not get purged as intended.
12) A "default pager" has now been created which cleans up the transition
of objects to the "swap" type. The previous checks throughout the code
for swp->pg_data != NULL were really ugly. This change also provides
the rudiments for future backing of "anonymous" memory by something
other than the swap pager (via the vnode pager, for example), and it
allows the decision about which of these pagers to use to be made
dynamically (although will need some additional decision code to do
this, of course).
13) (dyson) MAP_COPY has been deprecated and the corresponding "copy
object" code has been removed. MAP_COPY was undocumented and non-
standard. It was furthermore broken in several ways which caused its
behavior to degrade to MAP_PRIVATE. Binaries that use MAP_COPY will
continue to work correctly, but via the slightly different semantics
of MAP_PRIVATE.
14) (dyson) Sharing maps have been removed. It's marginal usefulness in a
threads design can be worked around in other ways. Both #12 and #13
were done to simplify the code and improve readability and maintain-
ability. (As were most all of these changes)
TODO:
1) Rewrite most of the vnode pager to use VOP_GETPAGES/PUTPAGES. Doing
this will reduce the vnode pager to a mere fraction of its current size.
2) Rewrite vm_fault and the swap/vnode pagers to use the clustering
information provided by the new haspage pager interface. This will
substantially reduce the overhead by eliminating a large number of
VOP_BMAP() calls. The VOP_BMAP() filesystem interface should be
improved to provide both a "behind" and "ahead" indication of
contiguousness.
3) Implement the extended features of pager_haspage in swap_pager_haspage().
It currently just says 0 pages ahead/behind.
4) Re-implement the swap device (swstrategy) in a more elegant way, perhaps
via a much more general mechanism that could also be used for disk
striping of regular filesystems.
5) Do something to improve the architecture of vm_object_collapse(). The
fact that it makes calls into the swap pager and knows too much about
how the swap pager operates really bothers me. It also doesn't allow
for collapsing of non-swap pager objects ("unnamed" objects backed by
other pagers).
1995-07-13 08:48:48 +00:00
|
|
|
#include <vm/vnode_pager.h>
|
1994-10-02 17:27:07 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <nfs/rpcv2.h>
|
1995-06-27 11:07:30 +00:00
|
|
|
#include <nfs/nfsproto.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <nfs/nfsnode.h>
|
|
|
|
#include <nfs/nfs.h>
|
|
|
|
#include <nfs/xdr_subs.h>
|
|
|
|
#include <nfs/nfsm_subs.h>
|
|
|
|
#include <nfs/nfsmount.h>
|
|
|
|
#include <nfs/nqnfs.h>
|
|
|
|
#include <nfs/nfsrtt.h>
|
|
|
|
|
|
|
|
#include <miscfs/specfs/specdev.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#ifdef ISO
|
|
|
|
#include <netiso/iso.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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_xdrneg1;
|
|
|
|
u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
|
1995-06-27 11:07:30 +00:00
|
|
|
rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
|
1994-05-24 10:09:53 +00:00
|
|
|
rpc_auth_kerb;
|
1995-06-27 11:07:30 +00:00
|
|
|
u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
/* And other global data */
|
|
|
|
static u_long nfs_xid = 0;
|
1995-12-17 21:14:36 +00:00
|
|
|
static 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
|
|
|
|
};
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
int nfs_mount_type;
|
1995-06-27 11:07:30 +00:00
|
|
|
int nfs_ticks;
|
|
|
|
|
1995-07-29 11:44:31 +00:00
|
|
|
struct nfs_reqq nfs_reqq;
|
|
|
|
struct nfssvc_sockhead nfssvc_sockhead;
|
|
|
|
int nfssvc_sockhead_flag;
|
|
|
|
struct nfsd_head nfsd_head;
|
|
|
|
int nfsd_head_flag;
|
|
|
|
struct nfs_bufq nfs_bufq;
|
|
|
|
struct nqtimerhead nqtimerhead;
|
|
|
|
struct nqfhhashhead *nqfhhashtbl;
|
|
|
|
u_long nqfhhash;
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1995-06-27 11:07:30 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
};
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#endif /* NFS_NOSERVER */
|
1995-06-27 11:07:30 +00:00
|
|
|
/*
|
|
|
|
* 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,
|
|
|
|
};
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1995-06-27 11:07:30 +00:00
|
|
|
/*
|
|
|
|
* 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,
|
|
|
|
};
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#endif /* NFS_NOSERVER */
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
extern struct nfsrtt nfsrtt;
|
|
|
|
extern time_t nqnfsstarttime;
|
|
|
|
extern int nqsrv_clockskew;
|
|
|
|
extern int nqsrv_writeslack;
|
|
|
|
extern int nqsrv_maxlease;
|
1995-06-27 11:07:30 +00:00
|
|
|
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;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1994-09-22 22:10:49 +00:00
|
|
|
#ifdef VFS_LKM
|
|
|
|
struct getfh_args;
|
|
|
|
extern int getfh(struct proc *, struct getfh_args *, int *);
|
|
|
|
struct nfssvc_args;
|
|
|
|
extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
|
|
|
|
#endif
|
|
|
|
|
1994-10-17 17:47:45 +00:00
|
|
|
LIST_HEAD(nfsnodehashhead, nfsnode);
|
|
|
|
|
1997-07-16 09:06:30 +00:00
|
|
|
int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Create the header for an rpc request packet
|
|
|
|
* The hsiz is the size of the rest of the nfs request header.
|
|
|
|
* (just used to decide if a cluster is a good idea)
|
|
|
|
*/
|
|
|
|
struct mbuf *
|
|
|
|
nfsm_reqh(vp, procid, hsiz, bposp)
|
|
|
|
struct vnode *vp;
|
|
|
|
u_long procid;
|
|
|
|
int hsiz;
|
|
|
|
caddr_t *bposp;
|
|
|
|
{
|
|
|
|
register struct mbuf *mb;
|
|
|
|
register u_long *tl;
|
|
|
|
register caddr_t bpos;
|
|
|
|
struct mbuf *mb2;
|
|
|
|
struct nfsmount *nmp;
|
|
|
|
int nqflag;
|
|
|
|
|
|
|
|
MGET(mb, M_WAIT, MT_DATA);
|
|
|
|
if (hsiz >= MINCLSIZE)
|
|
|
|
MCLGET(mb, M_WAIT);
|
|
|
|
mb->m_len = 0;
|
|
|
|
bpos = mtod(mb, caddr_t);
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* For NQNFS, add lease request.
|
|
|
|
*/
|
|
|
|
if (vp) {
|
|
|
|
nmp = VFSTONFS(vp->v_mount);
|
|
|
|
if (nmp->nm_flag & NFSMNT_NQNFS) {
|
|
|
|
nqflag = NQNFS_NEEDLEASE(vp, procid);
|
|
|
|
if (nqflag) {
|
|
|
|
nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
|
|
|
|
*tl++ = txdr_unsigned(nqflag);
|
|
|
|
*tl = txdr_unsigned(nmp->nm_leaseterm);
|
|
|
|
} else {
|
|
|
|
nfsm_build(tl, u_long *, NFSX_UNSIGNED);
|
|
|
|
*tl = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Finally, return values */
|
|
|
|
*bposp = bpos;
|
|
|
|
return (mb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build the RPC header and fill in the authorization info.
|
|
|
|
* The authorization string argument is only used when the credentials
|
|
|
|
* come from outside of the kernel.
|
|
|
|
* Returns the head of the mbuf list.
|
|
|
|
*/
|
|
|
|
struct mbuf *
|
1995-06-27 11:07:30 +00:00
|
|
|
nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
|
|
|
|
verf_str, mrest, mrest_len, mbp, xidp)
|
1994-05-24 10:09:53 +00:00
|
|
|
register struct ucred *cr;
|
1995-06-27 11:07:30 +00:00
|
|
|
int nmflag;
|
1994-05-24 10:09:53 +00:00
|
|
|
int procid;
|
|
|
|
int auth_type;
|
|
|
|
int auth_len;
|
|
|
|
char *auth_str;
|
1995-06-27 11:07:30 +00:00
|
|
|
int verf_len;
|
|
|
|
char *verf_str;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct mbuf *mrest;
|
|
|
|
int mrest_len;
|
|
|
|
struct mbuf **mbp;
|
|
|
|
u_long *xidp;
|
|
|
|
{
|
|
|
|
register struct mbuf *mb;
|
|
|
|
register u_long *tl;
|
|
|
|
register caddr_t bpos;
|
|
|
|
register int i;
|
|
|
|
struct mbuf *mreq, *mb2;
|
|
|
|
int siz, grpsiz, authsiz;
|
1996-07-16 10:19:45 +00:00
|
|
|
struct timeval tv;
|
|
|
|
static u_long base;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
authsiz = nfsm_rndup(auth_len);
|
|
|
|
MGETHDR(mb, M_WAIT, MT_DATA);
|
1995-06-27 11:07:30 +00:00
|
|
|
if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
|
1994-05-24 10:09:53 +00:00
|
|
|
MCLGET(mb, M_WAIT);
|
1995-06-27 11:07:30 +00:00
|
|
|
} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
|
|
|
|
MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
|
1994-05-24 10:09:53 +00:00
|
|
|
} else {
|
1995-06-27 11:07:30 +00:00
|
|
|
MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
mb->m_len = 0;
|
|
|
|
mreq = mb;
|
|
|
|
bpos = mtod(mb, caddr_t);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First the RPC header.
|
|
|
|
*/
|
1995-06-27 11:07:30 +00:00
|
|
|
nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
|
1996-07-16 10:19:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* derive initial xid from system time
|
|
|
|
* XXX time is invalid if root not yet mounted
|
|
|
|
*/
|
|
|
|
if (!base && (rootvp)) {
|
|
|
|
microtime(&tv);
|
|
|
|
base = tv.tv_sec << 12;
|
|
|
|
nfs_xid = base;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Skip zero xid if it should ever happen.
|
|
|
|
*/
|
1994-05-24 10:09:53 +00:00
|
|
|
if (++nfs_xid == 0)
|
|
|
|
nfs_xid++;
|
1996-07-16 10:19:45 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
*tl++ = *xidp = txdr_unsigned(nfs_xid);
|
|
|
|
*tl++ = rpc_call;
|
|
|
|
*tl++ = rpc_vers;
|
1995-06-27 11:07:30 +00:00
|
|
|
if (nmflag & NFSMNT_NQNFS) {
|
1994-05-24 10:09:53 +00:00
|
|
|
*tl++ = txdr_unsigned(NQNFS_PROG);
|
1995-06-27 11:07:30 +00:00
|
|
|
*tl++ = txdr_unsigned(NQNFS_VER3);
|
1994-05-24 10:09:53 +00:00
|
|
|
} else {
|
|
|
|
*tl++ = txdr_unsigned(NFS_PROG);
|
1995-06-27 11:07:30 +00:00
|
|
|
if (nmflag & NFSMNT_NFSV3)
|
|
|
|
*tl++ = txdr_unsigned(NFS_VER3);
|
|
|
|
else
|
|
|
|
*tl++ = txdr_unsigned(NFS_VER2);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1995-06-27 11:07:30 +00:00
|
|
|
if (nmflag & NFSMNT_NFSV3)
|
|
|
|
*tl++ = txdr_unsigned(procid);
|
|
|
|
else
|
|
|
|
*tl++ = txdr_unsigned(nfsv2_procid[procid]);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* And then the authorization cred.
|
|
|
|
*/
|
|
|
|
*tl++ = txdr_unsigned(auth_type);
|
|
|
|
*tl = txdr_unsigned(authsiz);
|
|
|
|
switch (auth_type) {
|
|
|
|
case RPCAUTH_UNIX:
|
|
|
|
nfsm_build(tl, u_long *, auth_len);
|
|
|
|
*tl++ = 0; /* stamp ?? */
|
|
|
|
*tl++ = 0; /* NULL hostname */
|
|
|
|
*tl++ = txdr_unsigned(cr->cr_uid);
|
|
|
|
*tl++ = txdr_unsigned(cr->cr_groups[0]);
|
|
|
|
grpsiz = (auth_len >> 2) - 5;
|
|
|
|
*tl++ = txdr_unsigned(grpsiz);
|
|
|
|
for (i = 1; i <= grpsiz; i++)
|
|
|
|
*tl++ = txdr_unsigned(cr->cr_groups[i]);
|
|
|
|
break;
|
1995-06-27 11:07:30 +00:00
|
|
|
case RPCAUTH_KERB4:
|
1994-05-24 10:09:53 +00:00
|
|
|
siz = auth_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(auth_str, bpos, i);
|
|
|
|
mb->m_len += i;
|
|
|
|
auth_str += i;
|
|
|
|
bpos += i;
|
|
|
|
siz -= i;
|
|
|
|
}
|
|
|
|
if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
|
|
|
|
for (i = 0; i < siz; i++)
|
|
|
|
*bpos++ = '\0';
|
|
|
|
mb->m_len += siz;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
};
|
1995-06-27 11:07:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
mb->m_next = mrest;
|
1995-06-27 11:07:30 +00:00
|
|
|
mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
|
1994-05-24 10:09:53 +00:00
|
|
|
mreq->m_pkthdr.rcvif = (struct ifnet *)0;
|
|
|
|
*mbp = mb;
|
|
|
|
return (mreq);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copies mbuf chain to the uio scatter/gather list
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsm_mbuftouio(mrep, uiop, siz, dpos)
|
|
|
|
struct mbuf **mrep;
|
|
|
|
register struct uio *uiop;
|
|
|
|
int siz;
|
|
|
|
caddr_t *dpos;
|
|
|
|
{
|
|
|
|
register char *mbufcp, *uiocp;
|
|
|
|
register int xfer, left, len;
|
|
|
|
register struct mbuf *mp;
|
|
|
|
long uiosiz, rem;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
mp = *mrep;
|
|
|
|
mbufcp = *dpos;
|
|
|
|
len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
|
|
|
|
rem = nfsm_rndup(siz)-siz;
|
|
|
|
while (siz > 0) {
|
|
|
|
if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
|
|
|
|
return (EFBIG);
|
|
|
|
left = uiop->uio_iov->iov_len;
|
|
|
|
uiocp = uiop->uio_iov->iov_base;
|
|
|
|
if (left > siz)
|
|
|
|
left = siz;
|
|
|
|
uiosiz = left;
|
|
|
|
while (left > 0) {
|
|
|
|
while (len == 0) {
|
|
|
|
mp = mp->m_next;
|
|
|
|
if (mp == NULL)
|
|
|
|
return (EBADRPC);
|
|
|
|
mbufcp = mtod(mp, caddr_t);
|
|
|
|
len = mp->m_len;
|
|
|
|
}
|
|
|
|
xfer = (left > len) ? len : left;
|
|
|
|
#ifdef notdef
|
|
|
|
/* Not Yet.. */
|
|
|
|
if (uiop->uio_iov->iov_op != NULL)
|
|
|
|
(*(uiop->uio_iov->iov_op))
|
|
|
|
(mbufcp, uiocp, xfer);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (uiop->uio_segflg == UIO_SYSSPACE)
|
|
|
|
bcopy(mbufcp, uiocp, xfer);
|
|
|
|
else
|
|
|
|
copyout(mbufcp, uiocp, xfer);
|
|
|
|
left -= xfer;
|
|
|
|
len -= xfer;
|
|
|
|
mbufcp += xfer;
|
|
|
|
uiocp += xfer;
|
|
|
|
uiop->uio_offset += xfer;
|
|
|
|
uiop->uio_resid -= xfer;
|
|
|
|
}
|
|
|
|
if (uiop->uio_iov->iov_len <= siz) {
|
|
|
|
uiop->uio_iovcnt--;
|
|
|
|
uiop->uio_iov++;
|
|
|
|
} else {
|
|
|
|
uiop->uio_iov->iov_base += uiosiz;
|
|
|
|
uiop->uio_iov->iov_len -= uiosiz;
|
|
|
|
}
|
|
|
|
siz -= uiosiz;
|
|
|
|
}
|
|
|
|
*dpos = mbufcp;
|
|
|
|
*mrep = mp;
|
|
|
|
if (rem > 0) {
|
|
|
|
if (len < rem)
|
|
|
|
error = nfs_adv(mrep, dpos, rem, len);
|
|
|
|
else
|
|
|
|
*dpos += rem;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1996-07-16 10:19:45 +00:00
|
|
|
* copies a uio scatter/gather list to an mbuf chain.
|
|
|
|
* NOTE: can ony handle iovcnt == 1
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsm_uiotombuf(uiop, mq, siz, bpos)
|
|
|
|
register struct uio *uiop;
|
|
|
|
struct mbuf **mq;
|
|
|
|
int siz;
|
|
|
|
caddr_t *bpos;
|
|
|
|
{
|
|
|
|
register char *uiocp;
|
|
|
|
register struct mbuf *mp, *mp2;
|
|
|
|
register int xfer, left, mlen;
|
|
|
|
int uiosiz, clflg, rem;
|
|
|
|
char *cp;
|
|
|
|
|
1996-07-16 10:19:45 +00:00
|
|
|
if (uiop->uio_iovcnt != 1)
|
|
|
|
panic("nfsm_uiotombuf: iovcnt != 1");
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
if (siz > MLEN) /* or should it >= MCLBYTES ?? */
|
|
|
|
clflg = 1;
|
|
|
|
else
|
|
|
|
clflg = 0;
|
|
|
|
rem = nfsm_rndup(siz)-siz;
|
|
|
|
mp = mp2 = *mq;
|
|
|
|
while (siz > 0) {
|
|
|
|
left = uiop->uio_iov->iov_len;
|
|
|
|
uiocp = uiop->uio_iov->iov_base;
|
|
|
|
if (left > siz)
|
|
|
|
left = siz;
|
|
|
|
uiosiz = left;
|
|
|
|
while (left > 0) {
|
|
|
|
mlen = M_TRAILINGSPACE(mp);
|
|
|
|
if (mlen == 0) {
|
|
|
|
MGET(mp, M_WAIT, MT_DATA);
|
|
|
|
if (clflg)
|
|
|
|
MCLGET(mp, M_WAIT);
|
|
|
|
mp->m_len = 0;
|
|
|
|
mp2->m_next = mp;
|
|
|
|
mp2 = mp;
|
|
|
|
mlen = M_TRAILINGSPACE(mp);
|
|
|
|
}
|
|
|
|
xfer = (left > mlen) ? mlen : left;
|
|
|
|
#ifdef notdef
|
|
|
|
/* Not Yet.. */
|
|
|
|
if (uiop->uio_iov->iov_op != NULL)
|
|
|
|
(*(uiop->uio_iov->iov_op))
|
|
|
|
(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (uiop->uio_segflg == UIO_SYSSPACE)
|
|
|
|
bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
|
|
|
|
else
|
|
|
|
copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
|
|
|
|
mp->m_len += xfer;
|
|
|
|
left -= xfer;
|
|
|
|
uiocp += xfer;
|
|
|
|
uiop->uio_offset += xfer;
|
|
|
|
uiop->uio_resid -= xfer;
|
|
|
|
}
|
1996-07-16 10:19:45 +00:00
|
|
|
uiop->uio_iov->iov_base += uiosiz;
|
|
|
|
uiop->uio_iov->iov_len -= uiosiz;
|
1994-05-24 10:09:53 +00:00
|
|
|
siz -= uiosiz;
|
|
|
|
}
|
|
|
|
if (rem > 0) {
|
|
|
|
if (rem > M_TRAILINGSPACE(mp)) {
|
|
|
|
MGET(mp, M_WAIT, MT_DATA);
|
|
|
|
mp->m_len = 0;
|
|
|
|
mp2->m_next = mp;
|
|
|
|
}
|
|
|
|
cp = mtod(mp, caddr_t)+mp->m_len;
|
|
|
|
for (left = 0; left < rem; left++)
|
|
|
|
*cp++ = '\0';
|
|
|
|
mp->m_len += rem;
|
|
|
|
*bpos = cp;
|
|
|
|
} else
|
|
|
|
*bpos = mtod(mp, caddr_t)+mp->m_len;
|
|
|
|
*mq = mp;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Help break down an mbuf chain by setting the first siz bytes contiguous
|
|
|
|
* pointed to by returned val.
|
|
|
|
* This is used by the macros nfsm_dissect and nfsm_dissecton for tough
|
|
|
|
* cases. (The macros use the vars. dpos and dpos2)
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsm_disct(mdp, dposp, siz, left, cp2)
|
|
|
|
struct mbuf **mdp;
|
|
|
|
caddr_t *dposp;
|
|
|
|
int siz;
|
|
|
|
int left;
|
|
|
|
caddr_t *cp2;
|
|
|
|
{
|
|
|
|
register struct mbuf *mp, *mp2;
|
|
|
|
register int siz2, xfer;
|
|
|
|
register caddr_t p;
|
|
|
|
|
|
|
|
mp = *mdp;
|
|
|
|
while (left == 0) {
|
|
|
|
*mdp = mp = mp->m_next;
|
|
|
|
if (mp == NULL)
|
|
|
|
return (EBADRPC);
|
|
|
|
left = mp->m_len;
|
|
|
|
*dposp = mtod(mp, caddr_t);
|
|
|
|
}
|
|
|
|
if (left >= siz) {
|
|
|
|
*cp2 = *dposp;
|
|
|
|
*dposp += siz;
|
|
|
|
} else if (mp->m_next == NULL) {
|
|
|
|
return (EBADRPC);
|
|
|
|
} else if (siz > MHLEN) {
|
|
|
|
panic("nfs S too big");
|
|
|
|
} else {
|
|
|
|
MGET(mp2, M_WAIT, MT_DATA);
|
|
|
|
mp2->m_next = mp->m_next;
|
|
|
|
mp->m_next = mp2;
|
|
|
|
mp->m_len -= left;
|
|
|
|
mp = mp2;
|
|
|
|
*cp2 = p = mtod(mp, caddr_t);
|
|
|
|
bcopy(*dposp, p, left); /* Copy what was left */
|
|
|
|
siz2 = siz-left;
|
|
|
|
p += left;
|
|
|
|
mp2 = mp->m_next;
|
|
|
|
/* Loop around copying up the siz2 bytes */
|
|
|
|
while (siz2 > 0) {
|
|
|
|
if (mp2 == NULL)
|
|
|
|
return (EBADRPC);
|
|
|
|
xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
|
|
|
|
if (xfer > 0) {
|
|
|
|
bcopy(mtod(mp2, caddr_t), p, xfer);
|
|
|
|
NFSMADV(mp2, xfer);
|
|
|
|
mp2->m_len -= xfer;
|
|
|
|
p += xfer;
|
|
|
|
siz2 -= xfer;
|
|
|
|
}
|
|
|
|
if (siz2 > 0)
|
|
|
|
mp2 = mp2->m_next;
|
|
|
|
}
|
|
|
|
mp->m_len = siz;
|
|
|
|
*mdp = mp2;
|
|
|
|
*dposp = mtod(mp2, caddr_t);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Advance the position in the mbuf chain.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_adv(mdp, dposp, offs, left)
|
|
|
|
struct mbuf **mdp;
|
|
|
|
caddr_t *dposp;
|
|
|
|
int offs;
|
|
|
|
int left;
|
|
|
|
{
|
|
|
|
register struct mbuf *m;
|
|
|
|
register int s;
|
|
|
|
|
|
|
|
m = *mdp;
|
|
|
|
s = left;
|
|
|
|
while (s < offs) {
|
|
|
|
offs -= s;
|
|
|
|
m = m->m_next;
|
|
|
|
if (m == NULL)
|
|
|
|
return (EBADRPC);
|
|
|
|
s = m->m_len;
|
|
|
|
}
|
|
|
|
*mdp = m;
|
|
|
|
*dposp = mtod(m, caddr_t)+offs;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy a string into mbufs for the hard cases...
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsm_strtmbuf(mb, bpos, cp, siz)
|
|
|
|
struct mbuf **mb;
|
|
|
|
char **bpos;
|
|
|
|
char *cp;
|
|
|
|
long siz;
|
|
|
|
{
|
1994-05-25 09:21:21 +00:00
|
|
|
register struct mbuf *m1 = 0, *m2;
|
1994-05-24 10:09:53 +00:00
|
|
|
long left, xfer, len, tlen;
|
|
|
|
u_long *tl;
|
|
|
|
int putsize;
|
|
|
|
|
|
|
|
putsize = 1;
|
|
|
|
m2 = *mb;
|
|
|
|
left = M_TRAILINGSPACE(m2);
|
|
|
|
if (left > 0) {
|
|
|
|
tl = ((u_long *)(*bpos));
|
|
|
|
*tl++ = txdr_unsigned(siz);
|
|
|
|
putsize = 0;
|
|
|
|
left -= NFSX_UNSIGNED;
|
|
|
|
m2->m_len += NFSX_UNSIGNED;
|
|
|
|
if (left > 0) {
|
|
|
|
bcopy(cp, (caddr_t) tl, left);
|
|
|
|
siz -= left;
|
|
|
|
cp += left;
|
|
|
|
m2->m_len += left;
|
|
|
|
left = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Loop around adding mbufs */
|
|
|
|
while (siz > 0) {
|
|
|
|
MGET(m1, M_WAIT, MT_DATA);
|
|
|
|
if (siz > MLEN)
|
|
|
|
MCLGET(m1, M_WAIT);
|
|
|
|
m1->m_len = NFSMSIZ(m1);
|
|
|
|
m2->m_next = m1;
|
|
|
|
m2 = m1;
|
|
|
|
tl = mtod(m1, u_long *);
|
|
|
|
tlen = 0;
|
|
|
|
if (putsize) {
|
|
|
|
*tl++ = txdr_unsigned(siz);
|
|
|
|
m1->m_len -= NFSX_UNSIGNED;
|
|
|
|
tlen = NFSX_UNSIGNED;
|
|
|
|
putsize = 0;
|
|
|
|
}
|
|
|
|
if (siz < m1->m_len) {
|
|
|
|
len = nfsm_rndup(siz);
|
|
|
|
xfer = siz;
|
|
|
|
if (xfer < len)
|
|
|
|
*(tl+(xfer>>2)) = 0;
|
|
|
|
} else {
|
|
|
|
xfer = len = m1->m_len;
|
|
|
|
}
|
|
|
|
bcopy(cp, (caddr_t) tl, xfer);
|
|
|
|
m1->m_len = len+tlen;
|
|
|
|
siz -= xfer;
|
|
|
|
cp += xfer;
|
|
|
|
}
|
|
|
|
*mb = m1;
|
|
|
|
*bpos = mtod(m1, caddr_t)+m1->m_len;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called once to initialize data structures...
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-02-10 02:22:35 +00:00
|
|
|
nfs_init(vfsp)
|
|
|
|
struct vfsconf *vfsp;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
|
|
|
register int i;
|
|
|
|
|
1995-06-27 11:07:30 +00:00
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
}
|
1997-02-10 02:22:35 +00:00
|
|
|
nfs_mount_type = vfsp->vfc_typenum;
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsrtt.pos = 0;
|
|
|
|
rpc_vers = txdr_unsigned(RPC_VER2);
|
|
|
|
rpc_call = txdr_unsigned(RPC_CALL);
|
|
|
|
rpc_reply = txdr_unsigned(RPC_REPLY);
|
|
|
|
rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
|
|
|
|
rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
|
|
|
|
rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
|
|
|
|
rpc_autherr = txdr_unsigned(RPC_AUTHERR);
|
|
|
|
rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
|
1995-06-27 11:07:30 +00:00
|
|
|
rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_prog = txdr_unsigned(NFS_PROG);
|
1995-06-27 11:07:30 +00:00
|
|
|
nqnfs_prog = txdr_unsigned(NQNFS_PROG);
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_true = txdr_unsigned(TRUE);
|
|
|
|
nfs_false = txdr_unsigned(FALSE);
|
1994-10-17 17:47:45 +00:00
|
|
|
nfs_xdrneg1 = txdr_unsigned(-1);
|
1995-06-27 11:07:30 +00:00
|
|
|
nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
|
|
|
|
if (nfs_ticks < 1)
|
|
|
|
nfs_ticks = 1;
|
1994-05-24 10:09:53 +00:00
|
|
|
/* Ensure async daemons disabled */
|
1996-11-06 10:53:16 +00:00
|
|
|
for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_iodwant[i] = (struct proc *)0;
|
1996-11-06 10:53:16 +00:00
|
|
|
nfs_iodmount[i] = (struct nfsmount *)0;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_nhinit(); /* Init the nfsnode table */
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsrv_init(0); /* Init server data structures */
|
|
|
|
nfsrv_initcache(); /* Init the server request cache */
|
1996-01-13 23:27:58 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the nqnfs server stuff.
|
|
|
|
*/
|
|
|
|
if (nqnfsstarttime == 0) {
|
|
|
|
nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
|
|
|
|
+ nqsrv_clockskew + nqsrv_writeslack;
|
|
|
|
NQLOADNOVRAM(nqnfsstarttime);
|
1994-10-17 17:47:45 +00:00
|
|
|
CIRCLEQ_INIT(&nqtimerhead);
|
|
|
|
nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize reply list and start timer
|
|
|
|
*/
|
1994-10-17 17:47:45 +00:00
|
|
|
TAILQ_INIT(&nfs_reqq);
|
1996-06-14 11:13:21 +00:00
|
|
|
|
1994-10-02 17:27:07 +00:00
|
|
|
nfs_timer(0);
|
1996-06-14 11:13:21 +00:00
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
|
1994-09-22 22:10:49 +00:00
|
|
|
/*
|
|
|
|
* Set up lease_check and lease_updatetime so that other parts
|
|
|
|
* of the system can call us, if we are loadable.
|
|
|
|
*/
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1997-02-10 02:22:35 +00:00
|
|
|
lease_check_hook = nqnfs_vop_lease_check;
|
1996-01-13 23:27:58 +00:00
|
|
|
#endif
|
1994-09-22 22:10:49 +00:00
|
|
|
lease_updatetime = nfs_lease_updatetime;
|
1997-02-10 02:22:35 +00:00
|
|
|
vfsp->vfc_refcount++; /* make us non-unloadable */
|
1994-09-22 22:10:49 +00:00
|
|
|
#ifdef VFS_LKM
|
|
|
|
sysent[SYS_nfssvc].sy_narg = 2;
|
|
|
|
sysent[SYS_nfssvc].sy_call = nfssvc;
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1994-09-22 22:10:49 +00:00
|
|
|
sysent[SYS_getfh].sy_narg = 2;
|
|
|
|
sysent[SYS_getfh].sy_call = getfh;
|
1995-06-27 11:07:30 +00:00
|
|
|
#endif
|
1994-09-22 22:10:49 +00:00
|
|
|
#endif
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
return (0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attribute cache routines.
|
|
|
|
* nfs_loadattrcache() - loads or updates the cache contents from attributes
|
|
|
|
* that are on the mbuf list
|
|
|
|
* nfs_getattrcache() - returns valid attributes if found in cache, returns
|
|
|
|
* error otherwise
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the attribute cache (that lives in the nfsnode entry) with
|
|
|
|
* the values on the mbuf list and
|
|
|
|
* Iff vap not NULL
|
|
|
|
* copy the attributes to *vaper
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_loadattrcache(vpp, mdp, dposp, vaper)
|
|
|
|
struct vnode **vpp;
|
|
|
|
struct mbuf **mdp;
|
|
|
|
caddr_t *dposp;
|
|
|
|
struct vattr *vaper;
|
|
|
|
{
|
|
|
|
register struct vnode *vp = *vpp;
|
|
|
|
register struct vattr *vap;
|
1995-06-27 11:07:30 +00:00
|
|
|
register struct nfs_fattr *fp;
|
1994-10-17 17:47:45 +00:00
|
|
|
register struct nfsnode *np;
|
1994-05-24 10:09:53 +00:00
|
|
|
register long t1;
|
1995-06-27 11:07:30 +00:00
|
|
|
caddr_t cp2;
|
|
|
|
int error = 0, rdev;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct mbuf *md;
|
|
|
|
enum vtype vtyp;
|
|
|
|
u_short vmode;
|
|
|
|
struct timespec mtime;
|
|
|
|
struct vnode *nvp;
|
1995-06-27 11:07:30 +00:00
|
|
|
int v3 = NFS_ISV3(vp);
|
1997-02-10 02:22:35 +00:00
|
|
|
struct proc *p = curproc;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
md = *mdp;
|
1995-06-27 11:07:30 +00:00
|
|
|
t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
|
|
|
|
if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
1995-06-27 11:07:30 +00:00
|
|
|
fp = (struct nfs_fattr *)cp2;
|
|
|
|
if (v3) {
|
|
|
|
vtyp = nfsv3tov_type(fp->fa_type);
|
|
|
|
vmode = fxdr_unsigned(u_short, fp->fa_mode);
|
1996-06-23 17:19:25 +00:00
|
|
|
rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
|
|
|
|
fxdr_unsigned(int, fp->fa3_rdev.specdata2));
|
1995-06-27 11:07:30 +00:00
|
|
|
fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
|
1994-05-24 10:09:53 +00:00
|
|
|
} else {
|
1995-06-27 11:07:30 +00:00
|
|
|
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;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1995-06-27 11:07:30 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* If v_type == VNON it is a new node, so fill in the v_type,
|
1995-05-30 08:16:23 +00:00
|
|
|
* n_mtime fields. Check to see if it represents a special
|
1994-05-24 10:09:53 +00:00
|
|
|
* device, and if so, check for a possible alias. Once the
|
|
|
|
* correct vnode has been obtained, fill in the rest of the
|
|
|
|
* information.
|
|
|
|
*/
|
|
|
|
np = VTONFS(vp);
|
1995-08-24 10:17:39 +00:00
|
|
|
if (vp->v_type != vtyp) {
|
1995-06-27 11:07:30 +00:00
|
|
|
vp->v_type = vtyp;
|
1994-05-24 10:09:53 +00:00
|
|
|
if (vp->v_type == VFIFO) {
|
|
|
|
vp->v_op = fifo_nfsv2nodeop_p;
|
|
|
|
}
|
|
|
|
if (vp->v_type == VCHR || vp->v_type == VBLK) {
|
|
|
|
vp->v_op = spec_nfsv2nodeop_p;
|
1994-10-02 17:27:07 +00:00
|
|
|
nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
|
|
|
|
if (nvp) {
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Discard unneeded vnode, but save its nfsnode.
|
1997-02-10 02:22:35 +00:00
|
|
|
* Since the nfsnode does not have a lock, its
|
|
|
|
* vnode lock has to be carried over.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1997-02-10 02:22:35 +00:00
|
|
|
nvp->v_vnlock = vp->v_vnlock;
|
|
|
|
vp->v_vnlock = NULL;
|
1994-05-24 10:09:53 +00:00
|
|
|
nvp->v_data = vp->v_data;
|
|
|
|
vp->v_data = NULL;
|
|
|
|
vp->v_op = spec_vnodeop_p;
|
|
|
|
vrele(vp);
|
|
|
|
vgone(vp);
|
|
|
|
/*
|
|
|
|
* Reinitialize aliased node.
|
|
|
|
*/
|
|
|
|
np->n_vnode = nvp;
|
|
|
|
*vpp = vp = nvp;
|
|
|
|
}
|
|
|
|
}
|
1996-09-19 18:21:32 +00:00
|
|
|
np->n_mtime = mtime.tv_sec;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
vap = &np->n_vattr;
|
|
|
|
vap->va_type = vtyp;
|
|
|
|
vap->va_mode = (vmode & 07777);
|
|
|
|
vap->va_rdev = (dev_t)rdev;
|
|
|
|
vap->va_mtime = mtime;
|
|
|
|
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
|
1995-06-27 11:07:30 +00:00
|
|
|
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;
|
1994-05-24 10:09:53 +00:00
|
|
|
} else {
|
1995-06-27 11:07:30 +00:00
|
|
|
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);
|
1994-05-24 10:09:53 +00:00
|
|
|
vap->va_flags = 0;
|
1996-09-19 18:21:32 +00:00
|
|
|
vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
|
|
|
|
vap->va_ctime.tv_nsec = 0;
|
1995-06-27 11:07:30 +00:00
|
|
|
vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
|
1994-05-24 10:09:53 +00:00
|
|
|
vap->va_filerev = 0;
|
|
|
|
}
|
|
|
|
if (vap->va_size != np->n_size) {
|
|
|
|
if (vap->va_type == VREG) {
|
|
|
|
if (np->n_flag & NMODIFIED) {
|
|
|
|
if (vap->va_size < np->n_size)
|
|
|
|
vap->va_size = np->n_size;
|
|
|
|
else
|
|
|
|
np->n_size = vap->va_size;
|
|
|
|
} else
|
|
|
|
np->n_size = vap->va_size;
|
|
|
|
vnode_pager_setsize(vp, (u_long)np->n_size);
|
|
|
|
} else
|
|
|
|
np->n_size = vap->va_size;
|
|
|
|
}
|
|
|
|
np->n_attrstamp = time.tv_sec;
|
|
|
|
if (vaper != NULL) {
|
|
|
|
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
|
|
|
|
if (np->n_flag & NCHG) {
|
1995-06-27 11:07:30 +00:00
|
|
|
if (np->n_flag & NACC)
|
|
|
|
vaper->va_atime = np->n_atim;
|
|
|
|
if (np->n_flag & NUPD)
|
|
|
|
vaper->va_mtime = np->n_mtim;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the time stamp
|
|
|
|
* If the cache is valid, copy contents to *vap and return 0
|
|
|
|
* otherwise return an error
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
nfs_getattrcache(vp, vaper)
|
|
|
|
register struct vnode *vp;
|
|
|
|
struct vattr *vaper;
|
|
|
|
{
|
|
|
|
register struct nfsnode *np = VTONFS(vp);
|
|
|
|
register struct vattr *vap;
|
|
|
|
|
1995-06-27 11:07:30 +00:00
|
|
|
if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
|
1994-05-24 10:09:53 +00:00
|
|
|
nfsstats.attrcache_misses++;
|
|
|
|
return (ENOENT);
|
|
|
|
}
|
|
|
|
nfsstats.attrcache_hits++;
|
|
|
|
vap = &np->n_vattr;
|
|
|
|
if (vap->va_size != np->n_size) {
|
|
|
|
if (vap->va_type == VREG) {
|
|
|
|
if (np->n_flag & NMODIFIED) {
|
|
|
|
if (vap->va_size < np->n_size)
|
|
|
|
vap->va_size = np->n_size;
|
|
|
|
else
|
|
|
|
np->n_size = vap->va_size;
|
|
|
|
} else
|
|
|
|
np->n_size = vap->va_size;
|
|
|
|
vnode_pager_setsize(vp, (u_long)np->n_size);
|
|
|
|
} else
|
|
|
|
np->n_size = vap->va_size;
|
|
|
|
}
|
|
|
|
bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
|
|
|
|
if (np->n_flag & NCHG) {
|
1995-06-27 11:07:30 +00:00
|
|
|
if (np->n_flag & NACC)
|
|
|
|
vaper->va_atime = np->n_atim;
|
|
|
|
if (np->n_flag & NUPD)
|
|
|
|
vaper->va_mtime = np->n_mtim;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
1997-07-16 09:06:30 +00:00
|
|
|
* Set up nameidata for a lookup() call and do it.
|
|
|
|
*
|
|
|
|
* If pubflag is set, this call is done for a lookup operation on the
|
|
|
|
* public filehandle. In that case we allow crossing mountpoints and
|
|
|
|
* absolute pathnames. However, the caller is expected to check that
|
|
|
|
* the lookup result is within the public fs, and deny access if
|
|
|
|
* it is not.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-07-16 09:06:30 +00:00
|
|
|
nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
|
1994-05-24 10:09:53 +00:00
|
|
|
register struct nameidata *ndp;
|
|
|
|
fhandle_t *fhp;
|
|
|
|
int len;
|
|
|
|
struct nfssvc_sock *slp;
|
1997-08-16 19:16:27 +00:00
|
|
|
struct sockaddr *nam;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct mbuf **mdp;
|
|
|
|
caddr_t *dposp;
|
1995-06-27 11:07:30 +00:00
|
|
|
struct vnode **retdirp;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
1997-07-16 09:06:30 +00:00
|
|
|
int kerbflag, pubflag;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
|
|
|
register int i, rem;
|
|
|
|
register struct mbuf *md;
|
1997-07-16 09:06:30 +00:00
|
|
|
register char *fromcp, *tocp, *cp;
|
|
|
|
struct iovec aiov;
|
|
|
|
struct uio auio;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct vnode *dp;
|
1997-07-16 09:06:30 +00:00
|
|
|
int error, rdonly, linklen;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct componentname *cnp = &ndp->ni_cnd;
|
|
|
|
|
1995-06-27 11:07:30 +00:00
|
|
|
*retdirp = (struct vnode *)0;
|
1997-09-21 04:24:27 +00:00
|
|
|
cnp->cn_pnbuf = zalloc(namei_zone);
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Copy the name from the mbuf list to ndp->ni_pnbuf
|
|
|
|
* and set the various ndp fields appropriately.
|
|
|
|
*/
|
|
|
|
fromcp = *dposp;
|
|
|
|
tocp = cnp->cn_pnbuf;
|
|
|
|
md = *mdp;
|
|
|
|
rem = mtod(md, caddr_t) + md->m_len - fromcp;
|
|
|
|
cnp->cn_hash = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
while (rem == 0) {
|
|
|
|
md = md->m_next;
|
|
|
|
if (md == NULL) {
|
|
|
|
error = EBADRPC;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
fromcp = mtod(md, caddr_t);
|
|
|
|
rem = md->m_len;
|
|
|
|
}
|
1997-07-16 09:06:30 +00:00
|
|
|
if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
|
1995-06-27 11:07:30 +00:00
|
|
|
error = EACCES;
|
1994-05-24 10:09:53 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
cnp->cn_hash += (unsigned char)*fromcp;
|
|
|
|
*tocp++ = *fromcp++;
|
|
|
|
rem--;
|
|
|
|
}
|
|
|
|
*tocp = '\0';
|
|
|
|
*mdp = md;
|
|
|
|
*dposp = fromcp;
|
|
|
|
len = nfsm_rndup(len)-len;
|
|
|
|
if (len > 0) {
|
|
|
|
if (rem >= len)
|
|
|
|
*dposp += len;
|
1997-07-22 15:35:57 +00:00
|
|
|
else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
|
1995-06-27 11:07:30 +00:00
|
|
|
goto out;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1997-07-16 09:06:30 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Extract and set starting directory.
|
|
|
|
*/
|
1997-07-16 09:06:30 +00:00
|
|
|
error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
|
|
|
|
nam, &rdonly, kerbflag, pubflag);
|
|
|
|
if (error)
|
1994-05-24 10:09:53 +00:00
|
|
|
goto out;
|
|
|
|
if (dp->v_type != VDIR) {
|
1996-08-21 21:56:23 +00:00
|
|
|
vrele(dp);
|
1994-05-24 10:09:53 +00:00
|
|
|
error = ENOTDIR;
|
|
|
|
goto out;
|
|
|
|
}
|
1997-07-16 09:06:30 +00:00
|
|
|
|
|
|
|
if (rdonly)
|
|
|
|
cnp->cn_flags |= RDONLY;
|
|
|
|
|
1997-07-22 15:35:57 +00:00
|
|
|
*retdirp = dp;
|
|
|
|
|
1997-07-16 09:06:30 +00:00
|
|
|
if (pubflag) {
|
|
|
|
/*
|
|
|
|
* Oh joy. For WebNFS, handle those pesky '%' escapes,
|
|
|
|
* and the 'native path' indicator.
|
|
|
|
*/
|
1997-09-21 04:24:27 +00:00
|
|
|
cp = zalloc(namei_zone);
|
1997-07-16 09:06:30 +00:00
|
|
|
fromcp = cnp->cn_pnbuf;
|
|
|
|
tocp = cp;
|
|
|
|
if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
|
|
|
|
switch ((unsigned char)*fromcp) {
|
|
|
|
case WEBNFS_NATIVE_CHAR:
|
|
|
|
/*
|
|
|
|
* 'Native' path for us is the same
|
|
|
|
* as a path according to the NFS spec,
|
|
|
|
* just skip the escape char.
|
|
|
|
*/
|
|
|
|
fromcp++;
|
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* More may be added in the future, range 0x80-0xff
|
|
|
|
*/
|
|
|
|
default:
|
|
|
|
error = EIO;
|
1997-09-21 04:24:27 +00:00
|
|
|
zfree(namei_zone, cp);
|
1997-07-16 09:06:30 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Translate the '%' escapes, URL-style.
|
|
|
|
*/
|
|
|
|
while (*fromcp != '\0') {
|
|
|
|
if (*fromcp == WEBNFS_ESC_CHAR) {
|
|
|
|
if (fromcp[1] != '\0' && fromcp[2] != '\0') {
|
|
|
|
fromcp++;
|
|
|
|
*tocp++ = HEXSTRTOI(fromcp);
|
|
|
|
fromcp += 2;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
error = ENOENT;
|
1997-09-21 04:24:27 +00:00
|
|
|
zfree(namei_zone, cp);
|
1997-07-16 09:06:30 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
*tocp++ = *fromcp++;
|
|
|
|
}
|
|
|
|
*tocp = '\0';
|
1997-09-21 04:24:27 +00:00
|
|
|
zfree(namei_zone, cnp->cn_pnbuf);
|
1997-07-16 09:06:30 +00:00
|
|
|
cnp->cn_pnbuf = cp;
|
|
|
|
}
|
|
|
|
|
|
|
|
ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
|
|
|
|
ndp->ni_segflg = UIO_SYSSPACE;
|
|
|
|
|
|
|
|
if (pubflag) {
|
|
|
|
ndp->ni_rootdir = rootvnode;
|
|
|
|
ndp->ni_loopcnt = 0;
|
|
|
|
if (cnp->cn_pnbuf[0] == '/')
|
|
|
|
dp = rootvnode;
|
|
|
|
} else {
|
1997-07-22 15:35:57 +00:00
|
|
|
cnp->cn_flags |= NOCROSSMOUNT;
|
1997-07-16 09:06:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cnp->cn_proc = p;
|
1995-06-27 11:07:30 +00:00
|
|
|
VREF(dp);
|
1997-07-16 09:06:30 +00:00
|
|
|
|
1997-07-22 15:35:57 +00:00
|
|
|
for (;;) {
|
1997-07-16 09:06:30 +00:00
|
|
|
cnp->cn_nameptr = cnp->cn_pnbuf;
|
1994-05-24 10:09:53 +00:00
|
|
|
ndp->ni_startdir = dp;
|
|
|
|
/*
|
|
|
|
* And call lookup() to do the real work
|
|
|
|
*/
|
1997-07-22 15:35:57 +00:00
|
|
|
error = lookup(ndp);
|
|
|
|
if (error)
|
1997-07-16 09:06:30 +00:00
|
|
|
break;
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Check for encountering a symbolic link
|
|
|
|
*/
|
1997-07-16 09:06:30 +00:00
|
|
|
if ((cnp->cn_flags & ISSYMLINK) == 0) {
|
|
|
|
nfsrv_object_create(ndp->ni_vp);
|
|
|
|
if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
|
|
|
|
cnp->cn_flags |= HASBUF;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} else {
|
1994-05-24 10:09:53 +00:00
|
|
|
if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
|
1997-07-16 09:06:30 +00:00
|
|
|
VOP_UNLOCK(ndp->ni_dvp, 0, p);
|
|
|
|
if (!pubflag) {
|
1994-05-24 10:09:53 +00:00
|
|
|
vrele(ndp->ni_dvp);
|
1997-07-16 09:06:30 +00:00
|
|
|
vput(ndp->ni_vp);
|
|
|
|
ndp->ni_vp = NULL;
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
1995-05-29 04:01:09 +00:00
|
|
|
|
1997-07-16 09:06:30 +00:00
|
|
|
if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
|
|
|
|
error = ELOOP;
|
|
|
|
break;
|
|
|
|
}
|
1997-07-22 15:35:57 +00:00
|
|
|
if (ndp->ni_pathlen > 1)
|
1997-09-21 04:24:27 +00:00
|
|
|
cp = zalloc(namei_zone);
|
1997-07-16 09:06:30 +00:00
|
|
|
else
|
|
|
|
cp = cnp->cn_pnbuf;
|
|
|
|
aiov.iov_base = cp;
|
|
|
|
aiov.iov_len = MAXPATHLEN;
|
|
|
|
auio.uio_iov = &aiov;
|
|
|
|
auio.uio_iovcnt = 1;
|
|
|
|
auio.uio_offset = 0;
|
|
|
|
auio.uio_rw = UIO_READ;
|
|
|
|
auio.uio_segflg = UIO_SYSSPACE;
|
|
|
|
auio.uio_procp = (struct proc *)0;
|
|
|
|
auio.uio_resid = MAXPATHLEN;
|
|
|
|
error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
|
|
|
|
if (error) {
|
|
|
|
badlink:
|
|
|
|
if (ndp->ni_pathlen > 1)
|
1997-09-21 04:24:27 +00:00
|
|
|
zfree(namei_zone, cp);
|
1997-07-16 09:06:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
linklen = MAXPATHLEN - auio.uio_resid;
|
|
|
|
if (linklen == 0) {
|
|
|
|
error = ENOENT;
|
|
|
|
goto badlink;
|
|
|
|
}
|
|
|
|
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
|
|
|
|
error = ENAMETOOLONG;
|
|
|
|
goto badlink;
|
|
|
|
}
|
|
|
|
if (ndp->ni_pathlen > 1) {
|
|
|
|
bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
|
1997-09-21 04:24:27 +00:00
|
|
|
zfree(namei_zone, cnp->cn_pnbuf);
|
1997-07-16 09:06:30 +00:00
|
|
|
cnp->cn_pnbuf = cp;
|
|
|
|
} else
|
|
|
|
cnp->cn_pnbuf[linklen] = '\0';
|
|
|
|
ndp->ni_pathlen += linklen;
|
|
|
|
vput(ndp->ni_vp);
|
|
|
|
dp = ndp->ni_dvp;
|
|
|
|
/*
|
|
|
|
* Check if root directory should replace current directory.
|
|
|
|
*/
|
|
|
|
if (cnp->cn_pnbuf[0] == '/') {
|
|
|
|
vrele(dp);
|
|
|
|
dp = ndp->ni_rootdir;
|
|
|
|
VREF(dp);
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1997-07-22 15:35:57 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
out:
|
1997-09-21 04:24:27 +00:00
|
|
|
zfree(namei_zone, cnp->cn_pnbuf);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A fiddled version of m_adj() that ensures null fill to a long
|
|
|
|
* boundary and only trims off the back end
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nfsm_adj(mp, len, nul)
|
|
|
|
struct mbuf *mp;
|
|
|
|
register int len;
|
|
|
|
int nul;
|
|
|
|
{
|
|
|
|
register struct mbuf *m;
|
|
|
|
register int count, i;
|
|
|
|
register char *cp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Trim from tail. Scan the mbuf chain,
|
|
|
|
* calculating its length and finding the last mbuf.
|
|
|
|
* If the adjustment only affects this mbuf, then just
|
|
|
|
* adjust and return. Otherwise, rescan and truncate
|
|
|
|
* after the remaining size.
|
|
|
|
*/
|
|
|
|
count = 0;
|
|
|
|
m = mp;
|
|
|
|
for (;;) {
|
|
|
|
count += m->m_len;
|
|
|
|
if (m->m_next == (struct mbuf *)0)
|
|
|
|
break;
|
|
|
|
m = m->m_next;
|
|
|
|
}
|
|
|
|
if (m->m_len > len) {
|
|
|
|
m->m_len -= len;
|
|
|
|
if (nul > 0) {
|
|
|
|
cp = mtod(m, caddr_t)+m->m_len-nul;
|
|
|
|
for (i = 0; i < nul; i++)
|
|
|
|
*cp++ = '\0';
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
count -= len;
|
|
|
|
if (count < 0)
|
|
|
|
count = 0;
|
|
|
|
/*
|
|
|
|
* Correct length for chain is "count".
|
|
|
|
* Find the mbuf with last data, adjust its length,
|
|
|
|
* and toss data from remaining mbufs on chain.
|
|
|
|
*/
|
|
|
|
for (m = mp; m; m = m->m_next) {
|
|
|
|
if (m->m_len >= count) {
|
|
|
|
m->m_len = count;
|
|
|
|
if (nul > 0) {
|
|
|
|
cp = mtod(m, caddr_t)+m->m_len-nul;
|
|
|
|
for (i = 0; i < nul; i++)
|
|
|
|
*cp++ = '\0';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
count -= m->m_len;
|
|
|
|
}
|
1994-10-02 17:27:07 +00:00
|
|
|
for (m = m->m_next;m;m = m->m_next)
|
1994-05-24 10:09:53 +00:00
|
|
|
m->m_len = 0;
|
|
|
|
}
|
|
|
|
|
1995-06-27 11:07:30 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* 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()
|
|
|
|
* - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
|
|
|
|
* - if not lockflag unlock it with VOP_UNLOCK()
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-07-16 09:06:30 +00:00
|
|
|
nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
|
1994-05-24 10:09:53 +00:00
|
|
|
fhandle_t *fhp;
|
|
|
|
int lockflag;
|
|
|
|
struct vnode **vpp;
|
|
|
|
struct ucred *cred;
|
|
|
|
struct nfssvc_sock *slp;
|
1997-08-16 19:16:27 +00:00
|
|
|
struct sockaddr *nam;
|
1994-05-24 10:09:53 +00:00
|
|
|
int *rdonlyp;
|
1995-06-27 11:07:30 +00:00
|
|
|
int kerbflag;
|
1997-07-16 09:06:30 +00:00
|
|
|
int pubflag;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
1997-02-10 02:22:35 +00:00
|
|
|
struct proc *p = curproc; /* XXX */
|
1994-05-24 10:09:53 +00:00
|
|
|
register struct mount *mp;
|
|
|
|
register int i;
|
|
|
|
struct ucred *credanon;
|
|
|
|
int error, exflags;
|
|
|
|
|
|
|
|
*vpp = (struct vnode *)0;
|
1997-07-16 09:06:30 +00:00
|
|
|
|
|
|
|
if (nfs_ispublicfh(fhp)) {
|
|
|
|
if (!pubflag || !nfs_pub.np_valid)
|
|
|
|
return (ESTALE);
|
|
|
|
fhp = &nfs_pub.np_handle;
|
|
|
|
}
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
mp = vfs_getvfs(&fhp->fh_fsid);
|
1994-10-02 17:27:07 +00:00
|
|
|
if (!mp)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (ESTALE);
|
1994-10-02 17:27:07 +00:00
|
|
|
error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
|
|
|
|
if (error)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
/*
|
|
|
|
* Check/setup credentials.
|
|
|
|
*/
|
|
|
|
if (exflags & MNT_EXKERB) {
|
1995-06-27 11:07:30 +00:00
|
|
|
if (!kerbflag) {
|
1994-05-24 10:09:53 +00:00
|
|
|
vput(*vpp);
|
1995-06-27 11:07:30 +00:00
|
|
|
return (NFSERR_AUTHERR | AUTH_TOOWEAK);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
1995-06-27 11:07:30 +00:00
|
|
|
} else if (kerbflag) {
|
|
|
|
vput(*vpp);
|
|
|
|
return (NFSERR_AUTHERR | AUTH_TOOWEAK);
|
1994-05-24 10:09:53 +00:00
|
|
|
} 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++)
|
|
|
|
cred->cr_groups[i] = credanon->cr_groups[i];
|
1994-10-17 17:47:45 +00:00
|
|
|
cred->cr_ngroups = i;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
if (exflags & MNT_EXRDONLY)
|
|
|
|
*rdonlyp = 1;
|
|
|
|
else
|
|
|
|
*rdonlyp = 0;
|
1995-04-21 02:58:49 +00:00
|
|
|
|
1996-08-21 21:56:23 +00:00
|
|
|
nfsrv_object_create(*vpp);
|
1995-04-21 02:58:49 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
if (!lockflag)
|
1997-02-10 02:22:35 +00:00
|
|
|
VOP_UNLOCK(*vpp, 0, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1997-07-16 09:06:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* WebNFS: check if a filehandle is a public filehandle. For v3, this
|
|
|
|
* means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
|
|
|
|
* transformed this to all zeroes in both cases, so check for it.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
nfs_ispublicfh(fhp)
|
|
|
|
fhandle_t *fhp;
|
|
|
|
{
|
|
|
|
char *cp = (char *)fhp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NFSX_V3FH; i++)
|
|
|
|
if (*cp++ != 0)
|
|
|
|
return (FALSE);
|
|
|
|
return (TRUE);
|
|
|
|
}
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#endif /* NFS_NOSERVER */
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* This function compares two net addresses by family and returns TRUE
|
|
|
|
* if they are the same host.
|
|
|
|
* If there is any doubt, return FALSE.
|
|
|
|
* The AF_INET family is handled as a special case so that address mbufs
|
|
|
|
* don't need to be saved to store "struct in_addr", which is only 4 bytes.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
netaddr_match(family, haddr, nam)
|
|
|
|
int family;
|
|
|
|
union nethostaddr *haddr;
|
1997-08-16 19:16:27 +00:00
|
|
|
struct sockaddr *nam;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
|
|
|
register struct sockaddr_in *inetaddr;
|
|
|
|
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
1997-08-16 19:16:27 +00:00
|
|
|
inetaddr = (struct sockaddr_in *)nam;
|
1994-05-24 10:09:53 +00:00
|
|
|
if (inetaddr->sin_family == AF_INET &&
|
|
|
|
inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
|
|
|
|
return (1);
|
|
|
|
break;
|
|
|
|
#ifdef ISO
|
|
|
|
case AF_ISO:
|
|
|
|
{
|
|
|
|
register struct sockaddr_iso *isoaddr1, *isoaddr2;
|
|
|
|
|
1997-08-16 19:16:27 +00:00
|
|
|
isoaddr1 = (struct sockaddr_iso *)nam;
|
|
|
|
isoaddr2 = (struct sockaddr_iso *)haddr->had_nam;
|
1994-05-24 10:09:53 +00:00
|
|
|
if (isoaddr1->siso_family == AF_ISO &&
|
|
|
|
isoaddr1->siso_nlen > 0 &&
|
|
|
|
isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
|
|
|
|
SAME_ISOADDR(isoaddr1, isoaddr2))
|
|
|
|
return (1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* ISO */
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
return (0);
|
|
|
|
}
|
These changes embody the support of the fully coherent merged VM buffer cache,
much higher filesystem I/O performance, and much better paging performance. It
represents the culmination of over 6 months of R&D.
The majority of the merged VM/cache work is by John Dyson.
The following highlights the most significant changes. Additionally, there are
(mostly minor) changes to the various filesystem modules (nfs, msdosfs, etc) to
support the new VM/buffer scheme.
vfs_bio.c:
Significant rewrite of most of vfs_bio to support the merged VM buffer cache
scheme. The scheme is almost fully compatible with the old filesystem
interface. Significant improvement in the number of opportunities for write
clustering.
vfs_cluster.c, vfs_subr.c
Upgrade and performance enhancements in vfs layer code to support merged
VM/buffer cache. Fixup of vfs_cluster to eliminate the bogus pagemove stuff.
vm_object.c:
Yet more improvements in the collapse code. Elimination of some windows that
can cause list corruption.
vm_pageout.c:
Fixed it, it really works better now. Somehow in 2.0, some "enhancements"
broke the code. This code has been reworked from the ground-up.
vm_fault.c, vm_page.c, pmap.c, vm_object.c
Support for small-block filesystems with merged VM/buffer cache scheme.
pmap.c vm_map.c
Dynamic kernel VM size, now we dont have to pre-allocate excessive numbers of
kernel PTs.
vm_glue.c
Much simpler and more effective swapping code. No more gratuitous swapping.
proc.h
Fixed the problem that the p_lock flag was not being cleared on a fork.
swap_pager.c, vnode_pager.c
Removal of old vfs_bio cruft to support the past pseudo-coherency. Now the
code doesn't need it anymore.
machdep.c
Changes to better support the parameter values for the merged VM/buffer cache
scheme.
machdep.c, kern_exec.c, vm_glue.c
Implemented a seperate submap for temporary exec string space and another one
to contain process upages. This eliminates all map fragmentation problems
that previously existed.
ffs_inode.c, ufs_inode.c, ufs_readwrite.c
Changes for merged VM/buffer cache. Add "bypass" support for sneaking in on
busy buffers.
Submitted by: John Dyson and David Greenman
1995-01-09 16:06:02 +00:00
|
|
|
|
1995-06-27 11:07:30 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
1996-01-13 23:27:58 +00:00
|
|
|
#ifndef NFS_NOSERVER
|
1995-06-27 11:07:30 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
These changes embody the support of the fully coherent merged VM buffer cache,
much higher filesystem I/O performance, and much better paging performance. It
represents the culmination of over 6 months of R&D.
The majority of the merged VM/cache work is by John Dyson.
The following highlights the most significant changes. Additionally, there are
(mostly minor) changes to the various filesystem modules (nfs, msdosfs, etc) to
support the new VM/buffer scheme.
vfs_bio.c:
Significant rewrite of most of vfs_bio to support the merged VM buffer cache
scheme. The scheme is almost fully compatible with the old filesystem
interface. Significant improvement in the number of opportunities for write
clustering.
vfs_cluster.c, vfs_subr.c
Upgrade and performance enhancements in vfs layer code to support merged
VM/buffer cache. Fixup of vfs_cluster to eliminate the bogus pagemove stuff.
vm_object.c:
Yet more improvements in the collapse code. Elimination of some windows that
can cause list corruption.
vm_pageout.c:
Fixed it, it really works better now. Somehow in 2.0, some "enhancements"
broke the code. This code has been reworked from the ground-up.
vm_fault.c, vm_page.c, pmap.c, vm_object.c
Support for small-block filesystems with merged VM/buffer cache scheme.
pmap.c vm_map.c
Dynamic kernel VM size, now we dont have to pre-allocate excessive numbers of
kernel PTs.
vm_glue.c
Much simpler and more effective swapping code. No more gratuitous swapping.
proc.h
Fixed the problem that the p_lock flag was not being cleared on a fork.
swap_pager.c, vnode_pager.c
Removal of old vfs_bio cruft to support the past pseudo-coherency. Now the
code doesn't need it anymore.
machdep.c
Changes to better support the parameter values for the merged VM/buffer cache
scheme.
machdep.c, kern_exec.c, vm_glue.c
Implemented a seperate submap for temporary exec string space and another one
to contain process upages. This eliminates all map fragmentation problems
that previously existed.
ffs_inode.c, ufs_inode.c, ufs_readwrite.c
Changes for merged VM/buffer cache. Add "bypass" support for sneaking in on
busy buffers.
Submitted by: John Dyson and David Greenman
1995-01-09 16:06:02 +00:00
|
|
|
int
|
1996-08-21 21:56:23 +00:00
|
|
|
nfsrv_object_create(struct vnode *vp) {
|
These changes embody the support of the fully coherent merged VM buffer cache,
much higher filesystem I/O performance, and much better paging performance. It
represents the culmination of over 6 months of R&D.
The majority of the merged VM/cache work is by John Dyson.
The following highlights the most significant changes. Additionally, there are
(mostly minor) changes to the various filesystem modules (nfs, msdosfs, etc) to
support the new VM/buffer scheme.
vfs_bio.c:
Significant rewrite of most of vfs_bio to support the merged VM buffer cache
scheme. The scheme is almost fully compatible with the old filesystem
interface. Significant improvement in the number of opportunities for write
clustering.
vfs_cluster.c, vfs_subr.c
Upgrade and performance enhancements in vfs layer code to support merged
VM/buffer cache. Fixup of vfs_cluster to eliminate the bogus pagemove stuff.
vm_object.c:
Yet more improvements in the collapse code. Elimination of some windows that
can cause list corruption.
vm_pageout.c:
Fixed it, it really works better now. Somehow in 2.0, some "enhancements"
broke the code. This code has been reworked from the ground-up.
vm_fault.c, vm_page.c, pmap.c, vm_object.c
Support for small-block filesystems with merged VM/buffer cache scheme.
pmap.c vm_map.c
Dynamic kernel VM size, now we dont have to pre-allocate excessive numbers of
kernel PTs.
vm_glue.c
Much simpler and more effective swapping code. No more gratuitous swapping.
proc.h
Fixed the problem that the p_lock flag was not being cleared on a fork.
swap_pager.c, vnode_pager.c
Removal of old vfs_bio cruft to support the past pseudo-coherency. Now the
code doesn't need it anymore.
machdep.c
Changes to better support the parameter values for the merged VM/buffer cache
scheme.
machdep.c, kern_exec.c, vm_glue.c
Implemented a seperate submap for temporary exec string space and another one
to contain process upages. This eliminates all map fragmentation problems
that previously existed.
ffs_inode.c, ufs_inode.c, ufs_readwrite.c
Changes for merged VM/buffer cache. Add "bypass" support for sneaking in on
busy buffers.
Submitted by: John Dyson and David Greenman
1995-01-09 16:06:02 +00:00
|
|
|
|
1995-06-28 12:01:13 +00:00
|
|
|
if ((vp == NULL) || (vp->v_type != VREG))
|
These changes embody the support of the fully coherent merged VM buffer cache,
much higher filesystem I/O performance, and much better paging performance. It
represents the culmination of over 6 months of R&D.
The majority of the merged VM/cache work is by John Dyson.
The following highlights the most significant changes. Additionally, there are
(mostly minor) changes to the various filesystem modules (nfs, msdosfs, etc) to
support the new VM/buffer scheme.
vfs_bio.c:
Significant rewrite of most of vfs_bio to support the merged VM buffer cache
scheme. The scheme is almost fully compatible with the old filesystem
interface. Significant improvement in the number of opportunities for write
clustering.
vfs_cluster.c, vfs_subr.c
Upgrade and performance enhancements in vfs layer code to support merged
VM/buffer cache. Fixup of vfs_cluster to eliminate the bogus pagemove stuff.
vm_object.c:
Yet more improvements in the collapse code. Elimination of some windows that
can cause list corruption.
vm_pageout.c:
Fixed it, it really works better now. Somehow in 2.0, some "enhancements"
broke the code. This code has been reworked from the ground-up.
vm_fault.c, vm_page.c, pmap.c, vm_object.c
Support for small-block filesystems with merged VM/buffer cache scheme.
pmap.c vm_map.c
Dynamic kernel VM size, now we dont have to pre-allocate excessive numbers of
kernel PTs.
vm_glue.c
Much simpler and more effective swapping code. No more gratuitous swapping.
proc.h
Fixed the problem that the p_lock flag was not being cleared on a fork.
swap_pager.c, vnode_pager.c
Removal of old vfs_bio cruft to support the past pseudo-coherency. Now the
code doesn't need it anymore.
machdep.c
Changes to better support the parameter values for the merged VM/buffer cache
scheme.
machdep.c, kern_exec.c, vm_glue.c
Implemented a seperate submap for temporary exec string space and another one
to contain process upages. This eliminates all map fragmentation problems
that previously existed.
ffs_inode.c, ufs_inode.c, ufs_readwrite.c
Changes for merged VM/buffer cache. Add "bypass" support for sneaking in on
busy buffers.
Submitted by: John Dyson and David Greenman
1995-01-09 16:06:02 +00:00
|
|
|
return 1;
|
1996-08-21 21:56:23 +00:00
|
|
|
return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1);
|
These changes embody the support of the fully coherent merged VM buffer cache,
much higher filesystem I/O performance, and much better paging performance. It
represents the culmination of over 6 months of R&D.
The majority of the merged VM/cache work is by John Dyson.
The following highlights the most significant changes. Additionally, there are
(mostly minor) changes to the various filesystem modules (nfs, msdosfs, etc) to
support the new VM/buffer scheme.
vfs_bio.c:
Significant rewrite of most of vfs_bio to support the merged VM buffer cache
scheme. The scheme is almost fully compatible with the old filesystem
interface. Significant improvement in the number of opportunities for write
clustering.
vfs_cluster.c, vfs_subr.c
Upgrade and performance enhancements in vfs layer code to support merged
VM/buffer cache. Fixup of vfs_cluster to eliminate the bogus pagemove stuff.
vm_object.c:
Yet more improvements in the collapse code. Elimination of some windows that
can cause list corruption.
vm_pageout.c:
Fixed it, it really works better now. Somehow in 2.0, some "enhancements"
broke the code. This code has been reworked from the ground-up.
vm_fault.c, vm_page.c, pmap.c, vm_object.c
Support for small-block filesystems with merged VM/buffer cache scheme.
pmap.c vm_map.c
Dynamic kernel VM size, now we dont have to pre-allocate excessive numbers of
kernel PTs.
vm_glue.c
Much simpler and more effective swapping code. No more gratuitous swapping.
proc.h
Fixed the problem that the p_lock flag was not being cleared on a fork.
swap_pager.c, vnode_pager.c
Removal of old vfs_bio cruft to support the past pseudo-coherency. Now the
code doesn't need it anymore.
machdep.c
Changes to better support the parameter values for the merged VM/buffer cache
scheme.
machdep.c, kern_exec.c, vm_glue.c
Implemented a seperate submap for temporary exec string space and another one
to contain process upages. This eliminates all map fragmentation problems
that previously existed.
ffs_inode.c, ufs_inode.c, ufs_readwrite.c
Changes for merged VM/buffer cache. Add "bypass" support for sneaking in on
busy buffers.
Submitted by: John Dyson and David Greenman
1995-01-09 16:06:02 +00:00
|
|
|
}
|
1996-01-13 23:27:58 +00:00
|
|
|
#endif /* NFS_NOSERVER */
|
1997-02-10 02:22:35 +00:00
|
|
|
|