nfs_srv.c revision 596bc2391087577f88d3665a6fb36aba8f1f2003
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
*/
#include <sys/sysmacros.h>
#include <vm/seg_kmem.h>
/*
* These are the interface routines for the server side of the
* Network File System. See the NFS version 2 protocol specification
* for a description of this interface.
*/
cred_t *);
/*
* Some "over the wire" UNIX file types. These are encoded
* into the mode. This needs to be fixed in the next rev.
*/
/*
* Get file attributes.
* Returns the current attributes of the file with the given fhandle.
*/
/* ARGSUSED */
void
{
int error;
return;
}
/*
* Do the getattr.
*/
/* check for overflows */
if (!error) {
/* Lie about the object type for a referral */
}
}
void *
{
return (fhp);
}
/*
* Set file attributes.
* Sets the attributes of the file with the given fhandle. Returns
* the new attributes.
*/
void
{
int error;
int flag;
int in_crit = 0;
return;
}
return;
}
if (error) {
return;
}
/*
* If the client is requesting a change to the mtime,
* but the nanosecond field is set to 1 billion, then
* this is a flag to the server that it should set the
* atime and mtime fields to the server's current time.
* The 1 billion number actually came from the client
* as 1 million, but the units in the over the wire
* request are microseconds instead of nanoseconds.
*
* This is an overload of the protocol and should be
* documented in the NFS Version 2 protocol specification.
*/
flag = 0;
} else
flag = ATTR_UTIME;
} else
flag = 0;
/*
* If the filesystem is exported with nosuid, then mask off
* the setuid and setgid bits.
*/
/*
* We need to specially handle size changes because it is
* possible for the client to create a file with modes
* which indicate read-only, but with the file opened for
* writing. If the client then tries to set the size of
* the file, then the normal access checking done in
* VOP_SETATTR would prevent the client from doing so,
* although it should be legal for it to do so. To get
* around this, we do the access checking for ourselves
* and then use VOP_SPACE which doesn't do the access
* checking which VOP_SETATTR does. VOP_SPACE can only
* operate on VREG files, let VOP_SETATTR handle the other
* extremely rare cases.
* Also the client should not be allowed to change the
* size of the file if there is a conflicting non-blocking
* mandatory lock in the region of change.
*/
if (nbl_need_check(vp)) {
in_crit = 1;
}
if (error) {
if (in_crit)
return;
}
if (in_crit) {
} else {
}
NULL)) {
}
}
}
if (in_crit)
} else
error = 0;
/*
* Do the setattr.
*/
}
/*
* check if the monitor on either vop_space or vop_setattr detected
* a delegation conflict and if so, mark the thread flag as
* wouldblock so that the response is dropped and the client will
* try again.
*/
return;
}
if (!error) {
/* check for overflows */
if (!error) {
}
}
/*
* Force modified metadata out to stable storage.
*/
}
void *
{
}
/*
* Directory lookup.
* Returns an fhandle and file attributes for file name in a directory.
*/
/* ARGSUSED */
void
{
int error;
char *name;
/*
* Trusted Extension doesn't support NFSv2. MOUNT
* will reject v2 clients. Need to prevent v2 client
* access via WebNFS here.
*/
return;
}
/*
* Disallow NULL paths
*/
return;
}
/*
* Allow lookups from the root - the default
* location of the public filehandle.
*/
} else {
return;
}
}
/*
* Not allow lookup beyond root.
* If the filehandle matches a filehandle of the exi,
* then the ".." refers beyond the root of an exported filesystem.
*/
return;
}
return;
}
/*
* If the public filehandle is used then allow
* a multi-component lookup, i.e. evaluate
* a pathname and follow symbolic links if
* necessary.
*
* This may result in a vnode in another filesystem
* which is OK as long as the filesystem is exported.
*/
if (PUBLIC_FH2(fhp)) {
&sec);
} else {
/*
* Do a normal single component lookup.
*/
}
if (!error) {
/* check for overflows */
if (!error) {
if (!error) {
else {
exi);
if (!error && publicfh_flag &&
}
}
}
}
/*
* If publicfh_flag is true then we have called rfs_publicfh_mclookup
* and have obtained a new exportinfo in exi which needs to be
* released. Note the the original exportinfo pointed to by exi
* will be released by the caller, comon_dispatch.
*/
/*
* If it's public fh, no 0x81, and client's flavor is
* invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
* Then set RPC status to AUTH_TOOWEAK in common_dispatch.
*/
if (auth_weak)
else
}
void *
{
return (da->da_fhandle);
}
/*
* Read symbolic link.
* Returns the string in the symbolic link at the given fhandle.
*/
/* ARGSUSED */
void
{
int error;
int is_referral = 0;
return;
}
if (error) {
return;
}
return;
}
/* We lied about the object type for a referral */
is_referral = 1;
/*
* XNFS and RFC1094 require us to return ENXIO if argument
* is not a link. BUGID 1138002.
*/
return;
}
/*
* Allocate data for pathname. This will be freed by rfs_rlfree.
*/
if (is_referral) {
char *s;
/* Get an artificial symlink based on a referral */
if (s == NULL)
else {
error = 0;
}
} else {
/*
* Set up io vector to read sym link data
*/
/*
* Do the readlink.
*/
if (!error)
}
}
/*
* XNFS and RFC1094 require us to return ENXIO if argument
* is not a link. UFS returns EINVAL if this is the case,
* so we do the mapping here. BUGID 1138002.
*/
else
}
void *
{
return (fhp);
}
/*
* Free data allocated by rfs_readlink
*/
void
{
}
/*
* Read data.
* Returns some data read from the file at the given fhandle.
*/
/* ARGSUSED */
void
{
int error;
int alloc_err = 0;
int in_crit = 0;
return;
}
return;
}
/*
* Enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with write requests.
*/
if (nbl_need_check(vp)) {
0, NULL)) {
return;
}
in_crit = 1;
}
/* check if a monitor detected a delegation conflict */
/* mark as wouldblock so response is dropped */
return;
}
if (error) {
if (in_crit)
return;
}
/*
* This is a kludge to allow reading of files created
* with no read permission. The owner of the file
* is always allowed to read it.
*/
if (error) {
/*
* Exec is the same as read over the net because
* of demand loading.
*/
}
if (error) {
if (in_crit)
return;
}
}
if (in_crit)
return;
}
/*
* In this case, status is NFS_OK, but there is no data
* to encode. So set rr_mp to NULL.
*/
goto done;
}
goto done;
}
} else {
/*
* mp will contain the data to be sent out in the read reply.
* This will be freed after the reply has been sent out (by the
* driver).
* Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so
* that the call to xdrmblk_putmblk() never fails.
*/
&alloc_err);
/*
* Set up io vector
*/
}
if (error) {
if (mp)
/*
* check if a monitor detected a delegation conflict and
* mark as wouldblock so response is dropped
*/
else
if (in_crit)
return;
}
/*
* Get attributes again so we can send the latest access
* time to the client side for his cache.
*/
if (error) {
if (mp)
if (in_crit)
return;
}
if (mp) {
} else {
}
}
}
done:
if (in_crit)
/* check for overflows */
}
/*
* Free data allocated by rfs_read
*/
void
{
}
}
void *
{
return (&ra->ra_fhandle);
}
#define MAX_IOVECS 12
#ifdef DEBUG
static int rfs_write_sync_hits = 0;
static int rfs_write_sync_misses = 0;
#endif
/*
* Write data to file.
* Returns attributes of a file after writing some data to it.
*
* Any changes made here, especially in error handling might have
* to also be done in rfs_write (which clusters write requests).
*/
void
{
int error;
mblk_t *m;
int iovcnt;
int in_crit = 0;
return;
}
return;
}
return;
}
if (error) {
return;
}
/*
* This is a kludge to allow writes of files created
* with read only permission. The owner of the file
* is always allowed to write it.
*/
if (error) {
return;
}
}
/*
* Can't access a mandatory lock file. This might cause
* the NFS service thread to block forever waiting for a
* lock to be released that will never be released.
*/
return;
}
/*
* We have to enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with ufs.
*/
if (nbl_need_check(vp)) {
in_crit = 1;
goto out;
}
}
/* check if a monitor detected a delegation conflict */
/* mark as wouldblock so response is dropped */
return;
}
/* Do the RDMA thing if necessary */
} else {
}
/*
* The limit is checked on the client. We
* should allow any size writes here.
*/
/*
* for now we assume no append mode
*/
/*
* We're changing creds because VM may fault and we need
* the cred of the current thread to be used if quota
* checking is enabled.
*/
} else {
iovcnt = 0;
iovcnt++;
if (iovcnt <= MAX_IOVECS) {
#ifdef DEBUG
#endif
} else {
#ifdef DEBUG
#endif
}
/*
* The limit is checked on the client. We
* should allow any size writes here.
*/
/*
* For now we assume no append mode.
*/
/*
* We're changing creds because VM may fault and we need
* the cred of the current thread to be used if quota
* checking is enabled.
*/
}
if (!error) {
/*
* Get attributes again so we send the latest mod
* time to the client side for his cache.
*/
/* check for overflows */
if (!error) {
}
}
out:
if (in_crit)
/* check if a monitor detected a delegation conflict */
/* mark as wouldblock so response is dropped */
else
}
struct rfs_async_write {
struct nfswriteargs *wa;
struct nfsattrstat *ns;
struct rfs_async_write *list;
};
struct rfs_async_write_list {
struct rfs_async_write *list;
struct rfs_async_write_list *next;
};
static kmutex_t rfs_async_write_lock;
#define MAXCLIOVECS 42
#ifdef DEBUG
static int rfs_write_hits = 0;
static int rfs_write_misses = 0;
#endif
/*
* Write data to file.
* Returns attributes of a file after writing some data to it.
*/
void
{
int error;
struct rfs_async_write_list *lp;
struct rfs_async_write_list *nlp;
struct rfs_async_write *rp;
struct rfs_async_write *nrp;
struct rfs_async_write *trp;
struct rfs_async_write *lrp;
int data_written;
int iovcnt;
mblk_t *m;
int count;
int rcount;
struct rfs_async_write nrpsp;
struct rfs_async_write_list nlpsp;
int in_crit = 0;
if (!rfs_write_async) {
return;
}
/*
* Initialize status to RFSWRITE_INITVAL instead of 0, since value of 0
* is considered an OK.
*/
/*
* Look to see if there is already a cluster started
* for this file.
*/
sizeof (fhandle_t)) == 0)
break;
}
/*
* If lp is non-NULL, then there is already a cluster
* started. We need to place ourselves in the cluster
* list in the right place as determined by starting
* offset. Conflicts with non-blocking mandatory locked
* regions will be checked when the cluster is processed.
*/
}
else
return;
}
/*
* No cluster started yet, start one and add ourselves
* to the list of clusters.
*/
if (rfs_async_write_head == NULL) {
} else {
}
/*
* Convert the file handle common to all of the requests
* in this cluster to a vnode.
*/
if (rfs_async_write_head == nlp)
else {
}
}
return;
}
/*
* Can only write regular files. Attempts to write any
* other file types fail with EISDIR.
*/
if (rfs_async_write_head == nlp)
else {
}
}
return;
}
/*
* Enter the critical region before calling VOP_RWLOCK, to avoid a
* deadlock with ufs.
*/
if (nbl_need_check(vp)) {
in_crit = 1;
}
/*
* Lock the file for writing. This operation provides
* the delay which allows clusters to grow.
*/
/* check if a monitor detected a delegation conflict */
if (in_crit)
/* mark as wouldblock so response is dropped */
if (rfs_async_write_head == nlp)
else {
}
}
}
return;
}
/*
* Disconnect this cluster from the list of clusters.
* The cluster that is being dealt with must be fixed
* in size after this point, so there is no reason
* to leave it on the list so that new requests can
* find it.
*
* The algorithm is that the first write request will
* create a cluster, convert the file handle to a
* vnode pointer, and then lock the file for writing.
* This request is not likely to be clustered with
* any others. However, the next request will create
* a new cluster and be blocked in VOP_RWLOCK while
* the first request is being processed. This delay
* will allow more requests to be clustered in this
* second cluster.
*/
if (rfs_async_write_head == nlp)
else {
}
/*
* Step through the list of requests in this cluster.
* We need to check permissions to make sure that all
* of the requests have sufficient permission to write
* the file. A cluster can be composed of requests
* from different clients and different users on each
* client.
*
* As a side effect, we also calculate the size of the
* byte range that this cluster encompasses.
*/
do {
continue;
}
if (!error) {
/*
* This is a kludge to allow writes of files
* created with read only permission. The
* owner of the file is always allowed to
* write it.
*/
}
}
/*
* Check for a conflict with a nbmand-locked region.
*/
}
if (error) {
continue;
}
/*
* Step through the cluster attempting to gather as many
* requests which are contiguous as possible. These
* contiguous requests are handled via one call to VOP_WRITE
* instead of different calls to VOP_WRITE. We also keep
* track of the fact that any data was written.
*/
data_written = 0;
do {
/*
* Skip any requests which are already marked as having an
* error.
*/
continue;
}
/*
* Count the number of iovec's which are required
* to handle this set of requests. One iovec is
* needed for each data buffer, whether addressed
* by wa_data or by the b_rptr pointers in the
* mblk chains.
*/
iovcnt = 0;
for (;;) {
iovcnt++;
else {
while (m != NULL) {
iovcnt++;
m = m->b_cont;
}
}
break;
}
}
if (iovcnt <= MAXCLIOVECS) {
#ifdef DEBUG
#endif
} else {
#ifdef DEBUG
#endif
}
/*
*/
count = 0;
do {
u.c_daddr3);
} else {
}
iovp++;
} else {
while (m != NULL) {
if (rcount < 0)
iovp++;
if (rcount <= 0)
break;
m = m->b_cont;
}
}
/*
* The limit is checked on the client. We
* should allow any size writes here.
*/
/*
* For now we assume no append mode.
*/
/*
* We're changing creds because VM may fault
* and we need the cred of the current
* thread to be used if quota * checking is
* enabled.
*/
/* check if a monitor detected a delegation conflict */
/* mark as wouldblock so response is dropped */
if (!error) {
data_written = 1;
/*
* Get attributes again so we send the latest mod
* time to the client side for his cache.
*/
if (!error)
}
/*
* Fill in the status responses for each request
* which was just handled. Also, copy the latest
* attributes in to the attribute responses if
* appropriate.
*/
do {
/* check for overflows */
if (!error) {
}
/*
* If any data was written at all, then we need to flush
* the data and metadata to stable storage.
*/
if (data_written) {
if (!error) {
}
}
if (in_crit)
}
}
}
void *
{
return (&wa->wa_fhandle);
}
/*
* Create a file.
* Creates a file with given attributes and returns those attributes
* and an fhandle for the new file.
*/
void
{
int error;
int lookuperr;
int in_crit = 0;
int mode;
int lookup_ok;
/*
* Disallow NULL paths
*/
return;
}
return;
}
if (error) {
return;
}
/*
* Must specify the mode.
*/
return;
}
/*
* This is a completely gross hack to make mknod
* work over the wire until we can wack the protocol
*/
else {
/*
* uncompress the received dev_t
* if the top half is zero indicating a request
* from an `older style' OS.
*/
else
}
/*
* uncompress the received dev_t
* if the top half is zero indicating a request
* from an `older style' OS.
*/
else
} else {
}
return;
}
/*
* Why was the choice made to use VWRITE as the mode to the
* call to VOP_CREATE ? This results in a bug. When a client
* opens a file that already exists and is RDONLY, the second
* open fails with an EACESS because of the mode.
* bug ID 1054648.
*/
lookup_ok = 0;
if (!error) {
lookup_ok = 1;
if (!error)
}
}
if (!lookup_ok) {
} else {
error = 0;
}
}
/*
* If file size is being modified on an already existing file
* make sure that there are no conflicting non-blocking mandatory
* locks in the region being manipulated. Return EACCES if there
* are conflicting locks.
*/
if (!lookuperr &&
goto out;
}
/*
* The file exists. Now check if it has any
* conflicting non-blocking mandatory locks
* in the region being changed.
*/
in_crit = 1;
if (!error) {
} else {
}
if (length) {
}
}
}
if (error) {
in_crit = 0;
}
}
}
if (!error) {
/*
* If filesystem is shared with nosuid the remove any
*/
if (!error) {
else
goto out;
}
/* check for overflows */
if (!error) {
if (!error) {
exi);
}
}
/*
* Force modified metadata out to stable storage.
*
* if a underlying vp exists, pass it to VOP_FSYNC
*/
else
}
if (in_crit) {
}
}
/*
* Force modified data and metadata out to stable storage.
*/
out:
}
void *
{
}
/*
* Remove a file.
* Remove named file from parent directory.
*/
void
{
int error = 0;
int in_crit = 0;
/*
* Disallow NULL paths
*/
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_STALE;
return;
}
*status = NFSERR_ROFS;
return;
}
/*
* Check for a conflict with a non-blocking mandatory share reservation.
*/
if (error != 0) {
return;
}
/*
* If the file is delegated to an v4 client, then initiate
* recall and drop this request (by setting T_WOULDBLOCK).
* The client will eventually re-transmit the request and
* (hopefully), by then, the v4 client will have returned
* the delegation.
*/
return;
}
if (nbl_need_check(targvp)) {
in_crit = 1;
goto out;
}
}
/*
* Force modified data and metadata out to stable storage.
*/
out:
if (in_crit)
}
void *
{
return (da->da_fhandle);
}
/*
* rename a file
* Give a file (from) a new name (to).
*/
void
{
int error = 0;
struct exportinfo *to_exi;
int in_crit = 0;
*status = NFSERR_STALE;
return;
}
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_XDEV;
return;
}
*status = NFSERR_STALE;
return;
}
*status = NFSERR_NOTDIR;
return;
}
/*
* Disallow NULL paths
*/
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_ROFS;
return;
}
/*
* Check for a conflict with a non-blocking mandatory share reservation.
*/
if (error != 0) {
return;
}
/* Check for delegations on the source file */
return;
}
/* Check for delegation on the file being renamed over, if it exists */
if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
return;
}
}
if (nbl_need_check(srcvp)) {
in_crit = 1;
goto out;
}
}
if (error == 0)
/*
* Force modified data and metadata out to stable storage.
*/
out:
if (in_crit)
}
void *
{
}
/*
* Link to a file.
* Create a file (to) which is a hard link to the given file (from).
*/
void
{
int error;
struct exportinfo *to_exi;
*status = NFSERR_STALE;
return;
}
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_XDEV;
return;
}
*status = NFSERR_STALE;
return;
}
*status = NFSERR_NOTDIR;
return;
}
/*
* Disallow NULL paths
*/
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_ROFS;
return;
}
/*
* Force modified data and metadata out to stable storage.
*/
}
void *
{
}
/*
* Symbolicly link to a file.
* Create a file (to) with the given attributes which is a symbolic link
* to the given path name (to).
*/
void
{
int error;
int lerror;
/*
* Disallow NULL paths
*/
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_STALE;
return;
}
*status = NFSERR_ROFS;
return;
}
if (error) {
return;
}
*status = NFSERR_INVAL;
return;
}
*status = NFSERR_ACCES;
return;
}
/*
* Force new data and metadata out to stable storage.
*/
if (!lerror) {
}
/*
* Force modified data and metadata out to stable storage.
*/
}
void *
{
}
/*
* Make a directory.
* Create a directory with the given name, parent directory, and attributes.
* Returns a file handle and attributes for the new directory.
*/
void
{
int error;
/*
* Disallow NULL paths
*/
return;
}
return;
}
return;
}
if (error) {
return;
}
return;
}
if (!error) {
/*
* Attribtutes of the newly created directory should
* be returned to the client.
*/
/* check for overflows */
if (!error) {
if (!error) {
}
}
/*
* Force new data and metadata out to stable storage.
*/
}
/*
* Force modified data and metadata out to stable storage.
*/
}
void *
{
}
/*
* Remove a directory.
* Remove the given directory name from the given parent directory.
*/
void
{
int error;
/*
* Disallow NULL paths
*/
*status = NFSERR_ACCES;
return;
}
*status = NFSERR_STALE;
return;
}
*status = NFSERR_ROFS;
return;
}
/*
* VOP_RMDIR now takes a new third argument (the current
* directory of the process). That's because someone
* wants to return EINVAL if one tries to remove ".".
* Of course, NFS servers have no idea what their
* clients' current directories are. We fake it by
* supplying a vnode known to exist and illegal to
* remove.
*/
/*
* Force modified data and metadata out to stable storage.
*/
/*
* System V defines rmdir to return EEXIST, not ENOTEMPTY,
* if the directory is not empty. A System V NFS server
* needs to map NFSERR_EXIST to NFSERR_NOTEMPTY to transmit
* over the wire.
*/
else
}
void *
{
return (da->da_fhandle);
}
/* ARGSUSED */
void
{
int error;
int iseof;
int ret;
return;
}
return;
}
if (error) {
goto bad;
}
goto bad;
}
/*
* Allocate data for entries. This will be freed by rfs_rddirfree.
*/
/*
* Set up io vector to read directory data
*/
/*
* read directory
*/
/*
* Clean up
*/
if (!error) {
/*
* set size and eof
*/
} else {
}
}
if (ret != 0) {
/*
* We had to drop one or more entries in order to fit
* during the character conversion. We need to patch
* up the size and eof info.
*/
}
}
bad:
#if 0 /* notyet */
/*
* Don't do this. It causes local disk writes when just
* reading the file and the overhead is deemed larger
* than the benefit.
*/
/*
* Force modified metadata out to stable storage.
*/
#endif
}
void *
{
}
void
{
}
/* ARGSUSED */
void
{
int error;
return;
}
if (!error) {
}
}
void *
{
return (fh);
}
static int
{
/*
* There was a sign extension bug in some VFS based systems
* which stored the mode as a short. When it would get
* assigned to a u_long, no sign extension would occur.
* It needed to, but this wasn't noticed because sa_mode
* would then get assigned back to the short, thus ignoring
* the upper 16 bits of sa_mode.
*
* To make this implementation work for both broken
* clients and good clients, we check for both versions
* of the mode.
*/
}
}
}
}
#ifndef _LP64
/* return error if time overflow */
return (EOVERFLOW);
#endif
/*
* nfs protocol defines times as unsigned so don't extend sign,
* unless sysadmin set nfs_allow_preepoch_time.
*/
}
#ifndef _LP64
/* return error if time overflow */
return (EOVERFLOW);
#endif
/*
* nfs protocol defines times as unsigned so don't extend sign,
* unless sysadmin set nfs_allow_preepoch_time.
*/
}
return (0);
}
};
/*
* check the following fields for overflow: nodeid, size, and time.
* There could be a problem when converting 64-bit LP64 fields
* into 32-bit ones. Return an error if there is an overflow.
*/
int
{
else
else
else
/*
* Do we need to check fsid for overflow? It is 64-bit in the
* vattr, but are bigger than 32 bit values supported?
*/
/*
* Check to make sure that the nodeid is representable over the
* wire without losing bits.
*/
return (EFBIG);
/*
* Check for big files here, instead of at the caller. See
* comments in cstat for large special file explanation.
*/
return (EFBIG);
/* UNKNOWN_SIZE | OVERFLOW */
} else
} else
/*
* If the vnode times overflow the 32-bit times that NFS2
* uses on the wire then return an error.
*/
if (!NFS_VAP_TIME_OK(vap)) {
return (EOVERFLOW);
}
/*
* If the dev_t will fit into 16 bits then compress
* it, otherwise leave it alone. See comments in
* nfs_client.c.
*/
else
/*
* This bit of ugliness is a *TEMPORARY* hack to preserve the
* over-the-wire protocols for named-pipe vnodes. It remaps the
* VFIFO type to the special over-the-wire type. (see note in nfs.h)
*
* BUYER BEWARE:
* If you are porting the NFS to a non-Sun server, you probably
* don't want to include the following block of code. The
* over-the-wire special file types will be changing with the
* NFS Protocol Revision.
*/
NA_SETFIFO(na);
return (0);
}
/*
* acl v2 support: returns approximate permission.
* default: returns minimal permission (more restrictive)
* aclok: returns maximal permission (less restrictive)
* This routine changes the permissions that are alaredy in *va.
* If a file has minimal ACL, i.e. aclcnt == MIN_ACL_ENTRIES,
* CLASS_OBJ is always the same as GROUP_OBJ entry.
*/
static void
{
int aclcnt;
int error;
/* dont care default acl */
if (!error) {
if (aclcnt > MIN_ACL_ENTRIES) {
/* non-trivial ACL */
/* maximal permissions */
grp_perm = 0;
other_perm = 0;
case USER_OBJ:
break;
case USER:
grp_perm |=
break;
case GROUP_OBJ:
grp_perm |=
break;
case GROUP:
break;
case OTHER_OBJ:
break;
case CLASS_OBJ:
break;
default:
break;
}
}
other_perm &= mask_perm;
other_perm |= other_orig;
} else {
/* minimal permissions */
grp_perm = 070;
other_perm = 07;
case USER_OBJ:
break;
case USER:
case CLASS_OBJ:
grp_perm &=
other_perm &=
break;
case GROUP_OBJ:
grp_perm &=
break;
case GROUP:
other_perm &=
break;
case OTHER_OBJ:
other_perm &=
break;
default:
break;
}
}
}
/* copy to va */
}
if (vsa.vsa_aclcnt)
}
}
void
rfs_srvrinit(void)
{
}
void
rfs_srvrfini(void)
{
}
static int
{
int wlist_len;
return (FALSE);
}
return (TRUE);
}