nfs3_srv.c revision f63200e6b1fbdcba7793746fa56b9f4121332f47
/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <sys/sysmacros.h>
#include <sys/systeminfo.h>
#include <rpc/rpc_rdma.h>
/*
* These are the interface routines for the server side of the
* Network File System. See the NFS version 3 protocol specification
* for a description of this interface.
*/
#ifdef DEBUG
int rfs3_do_pre_op_attr = 1;
int rfs3_do_post_op_attr = 1;
int rfs3_do_post_op_fh3 = 1;
#endif
static writeverf3 write3verf;
extern int nfs_loaned_buffers;
/* ARGSUSED */
void
{
int error;
goto out;
}
if (!error) {
/* Lie about the object type for a referral */
/* overflow error if time or size is out of range */
if (error)
goto out;
return;
}
out:
} else
}
void *
{
}
void
{
int error;
int flag;
int in_crit = 0;
goto out;
}
if (error)
goto out;
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
/*
* We need to specially handle size changes because of
* possible conflicting NBMAND locks. Get into critical
* region before VOP_GETATTR, so the size attribute is
* valid when checking conflicts.
*
* Also, check to see if the v4 side of the server has
* delegated this file. If so, then we return JUKEBOX to
* allow the client to retrasmit its request.
*/
if (nbl_need_check(vp)) {
in_crit = 1;
}
}
/*
* If we can't get the attributes, then we can't do the
* right access checking. So, we'll fail the request.
*/
if (error)
goto out;
#ifdef DEBUG
if (rfs3_do_pre_op_attr)
#else
#endif
goto out1;
}
goto out1;
}
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 the change.
*/
if (in_crit) {
} else {
}
NULL)) {
goto out;
}
}
}
}
/* check if a monitor detected a delegation conflict */
goto out1;
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified metadata out to stable storage.
*/
if (error)
goto out;
if (in_crit)
return;
out:
} else
out1:
if (in_crit)
}
}
void *
{
}
/* ARGSUSED */
void
{
int error;
/*
* Allow lookups from the root - the default
* location of the public filehandle.
*/
} else {
goto out;
}
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
}
#else
#endif
goto out1;
}
goto out1;
}
goto out1;
}
goto out1;
}
/*
* If the public filehandle is used then allow
* a multi-component lookup
*/
/*
* Since WebNFS may bypass MOUNT, we need to ensure this
* request didn't come from an unlabeled admin_low client.
*/
if (is_system_labeled() && error == 0) {
int addr_type;
void *ipaddr;
tsol_tpc_t *tp;
ipaddr = &((struct sockaddr_in6 *)
}
SUN_CIPSO) {
error = 1;
}
}
} else {
}
if (is_system_labeled() && error == 0) {
DOMINANCE_CHECK, exi)) {
error = 1;
}
}
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error)
goto out;
} else {
}
if (error) {
goto out;
}
/*
* 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, common_dispatch.
*/
if (publicfh_flag)
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* 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)
return;
out:
} else
out1:
}
void *
{
}
/* ARGSUSED */
void
{
int error;
int checkwriteperm;
goto out;
}
/*
* If the file system is exported read only, it is not appropriate
* to check write permissions for regular files and directories.
* Special files are interpreted by the client, so the underlying
* permissions are sent back to the client for interpretation.
*/
checkwriteperm = 0;
else
checkwriteperm = 1;
/*
* We need the mode so that we can correctly determine access
* permissions relative to a mandatory lock file. Access to
* mandatory lock files is denied on the server, so it might
* as well be reflected to the server during the open.
*/
if (error)
goto out;
#ifdef DEBUG
if (rfs3_do_post_op_attr)
#else
#endif
if (is_system_labeled()) {
} else
} else
}
if (error) {
goto out;
(!is_system_labeled() || admin_low_client ||
}
if (error) {
goto out;
} else if (!is_system_labeled() || admin_low_client ||
}
if (checkwriteperm &&
if (error) {
goto out;
}
}
if (checkwriteperm &&
if (error) {
goto out;
} else if (!is_system_labeled() || admin_low_client ||
}
if (error) {
goto out;
(!is_system_labeled() || admin_low_client ||
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
return;
out:
} else
}
void *
{
}
/* ARGSUSED */
void
{
int error;
char *data;
int is_referral = 0;
goto out;
}
if (error)
goto out;
#ifdef DEBUG
if (rfs3_do_post_op_attr)
#else
#endif
/* We lied about the object type for a referral */
is_referral = 1;
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
if (is_referral) {
char *s;
/* Get an artificial symlink based on a referral */
if (s == NULL)
else {
error = 0;
}
} else {
uio.uio_loffset = 0;
if (!error)
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/* Lie about object type again just to be consistent */
#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
if (error) {
goto out;
}
MAXPATHLEN + 1);
/*
* Even though the conversion failed, we return
* something. We just don't translate it.
*/
}
return;
out:
} else
out1:
}
void *
{
}
void
{
}
/*
* Server routine to handle read
* May handle RDMA data as well as mblks
*/
/* ARGSUSED */
void
{
int error;
int alloc_err = 0;
int in_crit = 0;
int need_rwunlock = 0;
int rdma_used = 0;
int loaned_buffers;
goto out;
}
rdma_used = 1;
/* use loaned buffers for TCP */
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
/*
* Enter the critical region before calling VOP_RWLOCK
* to avoid a deadlock with write requests.
*/
if (nbl_need_check(vp)) {
in_crit = 1;
NULL)) {
goto out;
}
}
/* check if a monitor detected a delegation conflict */
goto out1;
}
need_rwunlock = 1;
/*
* If we can't get the attributes, then we can't do the
* right access checking. So, we'll fail the request.
*/
if (error)
goto out;
#ifdef DEBUG
if (rfs3_do_post_op_attr)
#else
#endif
goto out1;
}
if (error) {
goto out;
if (error)
goto out;
}
}
goto out1;
}
if (in_crit)
/* RDMA */
goto done;
}
if (in_crit)
/* RDMA */
goto done;
}
/*
* do not allocate memory more the max. allowed
* transfer size
*/
if (loaned_buffers) {
/* Jump to do the read if successful */
/*
* Need to hold the vnode until after VOP_RETZCBUF()
* is called.
*/
goto doio_read;
}
uiop->uio_extflg = 0;
/* failure to setup for zero copy */
rfs_free_xuio((void *)uiop);
loaned_buffers = 0;
}
/*
* If returning data via RDMA Write, then grab the chunk list.
* If we aren't returning READ data w/RDMA_WRITE, then grab
* a mblk.
*/
if (rdma_used) {
} 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);
}
if (error) {
if (mp)
/* check if a monitor detected a delegation conflict */
goto out1;
}
goto out;
}
/* make mblk using zc buffers */
if (loaned_buffers) {
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
if (error)
else
} else
#else
if (error)
else
#endif
if (in_crit)
else
if (mp)
if (rdma_used) {
}
} else {
}
done:
return;
out:
} else
out1:
if (need_rwunlock)
if (in_crit)
}
}
void
{
}
}
void *
{
}
#define MAX_IOVECS 12
#ifdef DEBUG
static int rfs3_write_hits = 0;
static int rfs3_write_misses = 0;
#endif
void
{
int error;
mblk_t *m;
int iovcnt;
int ioflag;
int in_crit = 0;
int rwlock_ret = -1;
goto err;
}
if (is_system_labeled()) {
exi)) {
goto err1;
}
}
}
/*
* 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;
NULL)) {
goto err;
}
}
/* check if a monitor detected a delegation conflict */
rwlock_ret = -1;
goto err1;
}
/*
* If we can't get the attributes, then we can't do the
* right access checking. So, we'll fail the request.
*/
if (error)
goto err;
#ifdef DEBUG
if (!rfs3_do_pre_op_attr)
#endif
goto err1;
}
goto err1;
}
goto err1;
}
goto err;
goto err1;
}
goto out;
}
iovcnt = 0;
iovcnt++;
if (iovcnt <= MAX_IOVECS) {
#ifdef DEBUG
#endif
} else {
#ifdef DEBUG
#endif
}
iovcnt = 1;
} else {
iovcnt = 1;
}
ioflag = 0;
else {
goto err1;
}
/*
* 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 */
goto err1;
}
#ifdef DEBUG
if (!rfs3_do_post_op_attr)
#endif
if (error)
goto err;
/*
* If we were unable to get the V_WRITELOCK_TRUE, then we
* may not have accurate after attrs, so check if
* we have both attributes, they have a non-zero va_seq, and
* va_seq has changed by exactly one,
* if not, turn off the before attr.
*/
if (rwlock_ret != V_WRITELOCK_TRUE) {
}
}
goto out;
err:
} else
err1:
out:
if (rwlock_ret != -1)
if (in_crit)
}
}
void *
{
}
void
{
int error;
int in_crit = 0;
goto out;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out1;
}
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
/* This is really a Solaris EILSEQ */
goto out1;
}
/*
* Ensure no time overflows and that types match
*/
} else {
&va);
if (error)
goto out;
else {
/*
* During creation of file in non-exclusive mode
* if size of file is being set then make sure
* that if the file already exists that no conflicting
* non-blocking mandatory locks exists in the region
* being modified. If there are conflicting locks fail
* the operation with EACCES.
*/
/*
* Does file already exist?
*/
/*
* Check to see if the file has been delegated
* to a v4 client. If so, then begin recall of
* the delegation and return JUKEBOX to allow
* the client to retrasmit its request.
*/
if (!error &&
goto out1;
}
/*
* Check for NBMAND lock conflicts
*/
in_crit = 1;
NULL);
/*
* Can't check for conflicts, so return
* error.
*/
if (error)
goto out;
goto out;
}
} else if (tvp) {
}
}
}
}
/*
* Must specify the mode.
*/
goto out1;
}
/*
* If the filesystem is exported with nosuid, then mask off
* the setuid and setgid bits.
*/
/*
* The file open mode used is VWRITE. If the client needs
* some other semantic, then it should do the access checking
* itself. It would have been nice to have the file open mode
* passed as part of the arguments.
*/
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error) {
/*
* If we got something other than file already exists
* then just return this error. Otherwise, we got
* EEXIST. If we were doing a GUARDED create, then
* just return this error. Otherwise, we need to
* make sure that this wasn't a duplicate of an
* exclusive create request.
*
* The assumption is made that a non-exclusive create
* request will never return EEXIST.
*/
goto out;
/*
* Lookup the file so that we can get a vnode for it.
*/
if (error) {
/*
* We couldn't find the file that we thought that
* we just created. So, we'll just try creating
* it again.
*/
goto tryagain;
goto out;
}
/*
* If the file is delegated to a v4 client, go ahead
* and initiate recall, this create is a hint that a
* conflicting v3 open has occurred.
*/
goto out1;
}
/* % with INT32_MAX to prevent overflows */
goto out;
}
} else {
else
goto out1;
}
/*
* We need to check to make sure that the file got
* created to the indicated size. If not, we do a
* setattr to try to change the size, but we don't
* try too hard. This shouldn't a problem as most
* clients will only specifiy a size of zero which
* local file systems handle. However, even if
* the client does specify a non-zero size, it can
* still recover by checking the size of the file
* after it has created it and then issue a setattr
* request of its own to set the size of the file.
*/
}
}
#ifdef DEBUG
if (!rfs3_do_post_op_attr)
#endif
#ifdef DEBUG
if (!rfs3_do_post_op_fh3)
else {
#endif
if (error)
else
#ifdef DEBUG
}
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (in_crit)
}
return;
out:
} else
out1:
if (in_crit)
}
}
void *
{
}
void
{
int error;
goto out;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out1;
}
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
if (error)
goto out;
goto out1;
}
goto out1;
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (error)
goto out;
#ifdef DEBUG
if (!rfs3_do_post_op_fh3)
else {
#endif
if (error)
else
#ifdef DEBUG
}
#endif
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
return;
out:
} else
out1:
}
void *
{
}
void
{
int error;
goto err;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto err1;
}
goto err1;
}
goto err1;
}
if (is_system_labeled()) {
exi)) {
goto err1;
}
}
}
if (error)
goto err;
goto err1;
}
goto err1;
}
/* This is really a Solaris EILSEQ */
goto err1;
}
/* This is really a Solaris EILSEQ */
goto err1;
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error)
goto err;
/*
* Force modified data and metadata out to stable storage.
*/
if (error) {
goto out;
}
#ifdef DEBUG
if (!rfs3_do_post_op_fh3)
else {
#endif
if (error)
else
#ifdef DEBUG
}
#endif
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
goto out;
err:
} else
err1:
out:
}
void *
{
}
void
{
int error;
int mode;
goto out;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out1;
}
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
case NF3CHR:
case NF3BLK:
if (error)
goto out;
if (secpolicy_sys_devices(cr) != 0) {
goto out1;
}
else
break;
case NF3SOCK:
if (error)
goto out;
break;
case NF3FIFO:
if (error)
goto out;
break;
default:
goto out1;
}
/*
* Must specify the mode.
*/
goto out1;
}
goto out1;
}
mode = 0;
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (error)
goto out;
#ifdef DEBUG
if (!rfs3_do_post_op_fh3)
else {
#endif
if (error)
else
#ifdef DEBUG
}
#endif
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified metadata out to stable storage.
*
* if a underlying vp exists, pass it to VOP_FSYNC
*/
else
return;
out:
} else
out1:
}
void *
{
}
void
{
int error = 0;
goto err;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto err1;
}
goto err1;
}
goto err1;
}
goto err1;
}
if (is_system_labeled()) {
exi)) {
goto err1;
}
}
}
goto err1;
}
/*
* Check for a conflict with a non-blocking mandatory share
* reservation and V4 delegations
*/
if (error != 0)
goto err;
goto err1;
}
if (!nbl_need_check(targvp)) {
} else {
} else {
}
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (error)
goto err;
goto out;
err:
} else
err1:
out:
}
void *
{
}
void
{
int error;
goto err;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto err1;
}
goto err1;
}
goto err1;
}
goto err1;
}
if (is_system_labeled()) {
exi)) {
goto err1;
}
}
}
goto err1;
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (error) {
/*
* System V defines rmdir to return EEXIST, not ENOTEMPTY,
* if the directory is not empty. A System V NFS server
* needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
* over the wire.
*/
goto err;
}
goto out;
err:
} else
err1:
out:
}
void *
{
}
void
{
int error = 0;
struct exportinfo *to_exi;
goto err;
}
if (is_system_labeled()) {
exi)) {
goto err1;
}
}
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto err1;
}
goto err1;
}
goto err;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto err1;
}
goto err1;
}
goto err1;
}
goto err1;
}
if (is_system_labeled()) {
exi)) {
goto err1;
}
}
}
goto err1;
}
goto err1;
}
/*
* Check for a conflict with a non-blocking mandatory share
* reservation or V4 delegations.
*/
if (error != 0)
goto err;
/*
* If we rename a delegated file we should recall the
* delegation, since future opens should fail or would
* refer to a new file.
*/
goto err1;
}
/*
* Check for renaming over a delegated file. Check rfs4_deleg_policy
* first to avoid VOP_LOOKUP if possible.
*/
if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
goto err1;
}
}
if (!nbl_need_check(srcvp)) {
} else {
else
}
if (error == 0)
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else {
}
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (error)
goto err;
goto out;
err:
} else {
}
err1:
out:
}
void *
{
}
void
{
int error;
struct exportinfo *to_exi;
goto out;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
goto out;
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out1;
}
goto out1;
}
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
goto out1;
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else {
}
#else
#endif
/*
* Force modified data and metadata out to stable storage.
*/
if (error)
goto out;
return;
out:
} else
out1:
}
void *
{
}
/*
* This macro defines the size of a response which contains attribute
* information and one directory entry (whose length is specified by
* the macro parameter). If the incoming request is larger than this,
* then we are guaranteed to be able to return at one directory entry
* if one exists. Therefore, we do not need to check for
* NFS3ERR_TOOSMALL if the requested size is larger then this. If it
* is not, then we need to check to make sure that this error does not
* need to be returned.
*
* NFS3_READDIR_MIN_COUNT is comprised of following :
*
* status - 1 * BYTES_PER_XDR_UNIT
* attr. flag - 1 * BYTES_PER_XDR_UNIT
* cookie verifier - 2 * BYTES_PER_XDR_UNIT
* attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
* boolean - 1 * BYTES_PER_XDR_UNIT
* file id - 2 * BYTES_PER_XDR_UNIT
* directory name length - 1 * BYTES_PER_XDR_UNIT
* cookie - 2 * BYTES_PER_XDR_UNIT
* end of list - 1 * BYTES_PER_XDR_UNIT
* end of file - 1 * BYTES_PER_XDR_UNIT
* Name length of directory to the nearest byte
*/
#define NFS3_READDIR_MIN_COUNT(length) \
/* ARGSUSED */
void
{
int error;
char *data;
int iseof;
int bufsize;
int namlen;
goto out;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out1;
}
if (error)
goto out;
/*
* Now don't allow arbitrary count to alloc;
* allow the maximum not to exceed rfs3_tsize()
*/
/*
* Make sure that there is room to read at least one entry
* if any are available.
*/
else
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error) {
goto out;
}
/*
* If the count was not large enough to be able to guarantee
* to be able to return at least one entry, then need to
* check to see if NFS3ERR_TOOSMALL should be returned.
*/
/*
* bufsize is used to keep track of the size of the response.
* It is primed with:
* 1 for the status +
* 1 for the dir_attributes.attributes boolean +
* 2 for the cookie verifier
* all times BYTES_PER_XDR_UNIT to convert from XDR units
* to bytes. If there are directory attributes to be
* returned, then:
* NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
* time BYTES_PER_XDR_UNIT is added to account for them.
*/
/*
* An entry is composed of:
* 2 for the fileid +
* 1 for the length of the name +
* 2 for the cookie +
* all times BYTES_PER_XDR_UNIT to convert from
* XDR units to bytes, plus the length of the name
* rounded up to the nearest BYTES_PER_XDR_UNIT.
*/
}
/*
* We need to check to see if the number of bytes left
* to go into the buffer will actually fit into the
* buffer. This is calculated as the size of this
* entry plus:
* 1 for the eof indicator
* times BYTES_PER_XDR_UNIT to convert from from
* XDR units to bytes.
*/
goto out1;
}
}
/*
* Have a valid readir buffer for the native character
* set. Need to check if a conversion is necessary and
* potentially rewrite the whole buffer. Note that if the
* conversion expands names enough, the structure may not
* fit. In this case, we need to drop entries until if fits
* and patch the counts in order that the next readdir will
* get the correct entries.
*/
#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
return;
out:
} else
out1:
}
}
void *
{
}
void
{
}
#ifdef nextdp
#endif
/*
* This macro computes the size of a response which contains
* one directory entry including the attributes as well as file handle.
* If the incoming request is larger than this, then we are guaranteed to be
* able to return at least one more directory entry if one exists.
*
* NFS3_READDIRPLUS_ENTRY is made up of the following:
*
* boolean - 1 * BYTES_PER_XDR_UNIT
* file id - 2 * BYTES_PER_XDR_UNIT
* directory name length - 1 * BYTES_PER_XDR_UNIT
* cookie - 2 * BYTES_PER_XDR_UNIT
* attribute flag - 1 * BYTES_PER_XDR_UNIT
* attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
* status byte for file handle - 1 * BYTES_PER_XDR_UNIT
* length of a file handle - 1 * BYTES_PER_XDR_UNIT
* Maximum length of a file handle (NFS3_MAXFHSIZE)
* name length of the entry to the nearest bytes
*/
#define NFS3_READDIRPLUS_ENTRY(namelen) \
static int rfs3_readdir_unit = MAXBSIZE;
/* ARGSUSED */
void
{
int error;
char *data;
int iseof;
int size = 0;
int nents = 0;
int bufsize = 0;
int entrysize = 0;
int tofit = 0;
int rd_unit = rfs3_readdir_unit;
int prev_len;
int space_left;
int i;
goto out;
}
if (is_system_labeled()) {
char *, "got client label from request(1)",
exi)) {
goto out1;
}
}
}
#ifdef DEBUG
if (rfs3_do_pre_op_attr) {
} else
#else
#endif
goto out;
}
if (error)
goto out;
/*
* Don't allow arbitrary counts for allocation
*/
/*
* Make sure that there is room to read at least one entry
* if any are available
*/
/*
* This allocation relies on a minimum directory entry
* being roughly 24 bytes. Therefore, the namlen array
* will have enough space based on the maximum number of
* entries to read.
*/
/*
* bufsize is used to keep track of the size of the response as we
* get post op attributes and filehandles for each entry. This is
* an optimization as the server may have read more entries than will
* fit in the buffer specified by maxcount. We stop calculating
* post op attributes and filehandles once we have exceeded maxcount.
* This will minimize the effect of truncation.
*
* It is primed with:
* 1 for the status +
* 1 for the dir_attributes.attributes boolean +
* 2 for the cookie verifier
* all times BYTES_PER_XDR_UNIT to convert from XDR units
* to bytes. If there are directory attributes to be
* returned, then:
* NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
* time BYTES_PER_XDR_UNIT is added to account for them.
*/
/*
* Here we make a check so that our read unit is not larger than
* the space left in the buffer.
*/
if (error) {
goto out;
}
if (nents == 0) {
goto out1;
}
/*
* We could not get any more entries, so get the attributes
* and filehandle for the entries already obtained.
*/
goto good;
}
/*
* We estimate the size of the response by assuming the
* entry exists and attributes and filehandle are also valid
*/
size > 0;
nents++;
continue;
}
/*
* We need to check to see if the number of bytes left
* to go into the buffer will actually fit into the
* buffer. This is calculated as the size of this
* entry plus:
* 1 for the eof indicator
* times BYTES_PER_XDR_UNIT to convert from XDR units
* to bytes.
*
* Also check the dircount limit against the first entry read
*
*/
/*
* We make a check here to see if this was the
* first entry being measured. If so, then maxcount
* was too small to begin with and so we need to
* return with NFS3ERR_TOOSMALL.
*/
if (nents == 0) {
goto out1;
}
goto good;
}
nents++;
}
/*
* If there is enough room to fit at least 1 more entry including
* post op attributes and filehandle in the buffer AND that we haven't
* exceeded dircount then go back and get some more.
*/
if (!iseof &&
goto getmoredents;
/* else, fall through */
}
good:
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
for (i = 0; i < nents; i++) {
continue;
}
if (error) {
continue;
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/* Lie about the object type for a referral */
#ifdef DEBUG
if (!rfs3_do_post_op_fh3)
else {
#endif
if (!error)
else
#ifdef DEBUG
}
#endif
}
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.
*/
if (iseof)
}
#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
return;
out:
} else {
}
out1:
}
}
void *
{
}
void
{
}
}
/* ARGSUSED */
void
{
int error;
goto out;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error)
goto out;
else
else
else
return;
out:
} else
out1:
}
void *
{
}
void
{
ulong_t l = 0;
int error;
} else
goto out;
}
if (is_system_labeled()) {
exi)) {
goto out;
}
}
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
/*
* Large file spec: want maxfilesize based on limit of
* underlying filesystem. We can guess 2^31-1 if need be.
*/
if (error) {
goto out;
}
/*
* If the underlying file system does not support _PC_FILESIZEBITS,
* return a reasonable default. Note that error code on VOP_PATHCONF
* will be 0, even if the underlying file system does not support
* _PC_FILESIZEBITS.
*/
if (l == (ulong_t)-1) {
} else {
if (l >= (sizeof (uint64_t) * 8))
else
}
return;
out:
}
void *
{
}
/* ARGSUSED */
void
{
int error;
goto out;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error)
goto out;
if (error)
goto out;
if (error)
goto out;
if (val == 1)
else
if (error)
goto out;
if (val == 1)
else
return;
out:
} else
out1:
}
void *
{
}
void
{
int error;
goto out;
}
/*
* If we can't get the attributes, then we can't do the
* right access checking. So, we'll fail the request.
*/
if (error)
goto out;
#ifdef DEBUG
if (rfs3_do_pre_op_attr)
else
#else
#endif
goto out1;
}
goto out1;
}
if (is_system_labeled()) {
exi)) {
goto out1;
}
}
}
goto out;
#ifdef DEBUG
if (rfs3_do_post_op_attr) {
} else
#else
#endif
if (error)
goto out;
return;
out:
} else
out1:
}
void *
{
}
static int
{
}
}
}
return (EINVAL);
}
#ifndef _LP64
/* check time validity */
return (EOVERFLOW);
#endif
/*
* nfs protocol defines times as unsigned so don't extend sign,
* unless sysadmin set nfs_allow_preepoch_time.
*/
}
#ifndef _LP64
/* check time validity */
return (EOVERFLOW);
#endif
/*
* nfs protocol defines times as unsigned so don't extend sign,
* unless sysadmin set nfs_allow_preepoch_time.
*/
}
return (0);
}
};
static int
{
/* Return error if time or size overflow */
return (EOVERFLOW);
}
else
else
return (0);
}
static int
{
/* Return error if time or size overflow */
return (EOVERFLOW);
}
return (0);
}
static void
{
/* don't return attrs if time overflow */
} else
}
void
{
/* don't return attrs if time overflow */
} else
}
static void
{
}
void
rfs3_srvrinit(void)
{
struct rfs3_verf_overlay {
int ts; /* a unique timestamp */
} *verfp;
/*
* The following algorithm attempts to find a unique verifier
* to be used as the write verifier returned from the server
* to the client. It is important that this verifier change
* whenever the server reboots. Of secondary importance, it
* is important for the verifier to be unique between two
* different servers.
*
* Thus, an attempt is made to use the system hostid and the
* current time in seconds when the nfssrv kernel module is
* loaded. It is assumed that an NFS server will not be able
* to boot and then to reboot in less than a second. If the
* hostid has not been set, then the current high resolution
* time is used. This will ensure different verifiers each
* time the server reboots and minimize the chances that two
* different servers will have the same verifier.
*/
#ifndef lint
/*
* We ASSERT that this constant logic expression is
* always true because in the past, it wasn't.
*/
#endif
gethrestime(&now);
}
static int
{
int wlist_len;
return (FALSE);
}
return (TRUE);
}
void
rfs3_srvrfini(void)
{
/* Nothing to do */
}