/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <rpc/auth_unix.h>
#include <rpc/auth_des.h>
#include <nfs/nfs_dispatch.h>
#include <nfs/nfs4_drc.h>
#define NFS4_MAX_MINOR_VERSION 0
/*
* This is the duplicate request cache for NFSv4
*/
/*
* The default size of the duplicate request cache
*/
/*
* The number of buckets we'd like to hash the
* replies into.. do not change this on the fly.
*/
/*
* Initialize a duplicate request cache.
*/
{
}
return (drc);
}
/*
* Destroy a duplicate request cache.
*/
void
{
/* iterate over the dr_cache and free the enties */
}
}
/*
* rfs4_dr_chstate:
*
* Change the state of a rfs4_dupreq. If it's not in transition
* to the FREE state, return. If we are moving to the FREE state
* then we need to clean up the compound results and move the entry
* to the end of the list.
*/
void
{
if (new_state != NFS4_DUP_FREE)
return;
/*
* Remove entry from the bucket and
* dr_cache list, free compound results.
*/
}
/*
* rfs4_alloc_dr:
*
* Malloc a new one if we have not reached our maximum cache
* limit, otherwise pick an entry off the tail -- Use if it
* is marked as NFS4_DUP_FREE, or is an entry in the
* NFS4_DUP_REPLAY state.
*/
{
/*
* Have we hit the cache limit yet ?
*/
/*
* nope, so let's malloc a new one
*/
return (drp);
}
/*
* Cache is all allocated now traverse the list
* backwards to find one we can reuse.
*/
case NFS4_DUP_FREE:
rfs4_dupreq_t *, drp_tail);
return (drp_tail);
/* NOTREACHED */
case NFS4_DUP_REPLAY:
/* grab it. */
rfs4_dupreq_t *, drp_tail);
return (drp_tail);
/* NOTREACHED */
}
}
return (NULL);
}
/*
* rfs4_find_dr:
*
* Search for an entry in the duplicate request cache by
* calculating the hash index based on the XID, and examining
* the entries in the hash bucket. If we find a match, return.
* Once we have searched the bucket we call rfs4_alloc_dr() to
* allocate a new entry, or reuse one that is available.
*/
int
{
int bktdex;
/*
* Get the XID, calculate the bucket and search to
* see if we need to replay from the cache.
*/
int, bktdex,
/*
* Search the bucket for a matching xid and address.
*/
/*
* Found a match so REPLAY the Reply
*/
rfs4_dupreq_t *, drp);
return (NFS4_DUP_REPLAY);
}
/*
* This entry must be in transition, so return
* the 'pending' status.
*/
return (NFS4_DUP_PENDING);
}
}
/*
* The DRC is full and all entries are in use. Upper function
* should error out this request and force the client to
* retransmit -- effectively this is a resource issue. NFSD
* threads tied up with native File System, or the cache size
* is too small for the server load.
*/
return (NFS4_DUP_ERROR);
/*
* Init the state to NEW.
*/
/*
* If needed, resize the address buffer
*/
/*
* If the malloc fails, mark the entry
* as free and put on the tail.
*/
return (NFS4_DUP_ERROR);
}
}
/*
* Copy the address.
*/
/*
* Insert at the head of the bucket and
* the drc lists..
*/
return (NFS4_DUP_NEW);
}
/*
*
* This function handles the duplicate request cache,
* NULL_PROC and COMPOUND procedure calls for NFSv4;
*
* Passed into this function are:-
*
* disp A pointer to our dispatch table entry
* req The request to process
* xprt The server transport handle
* ap A pointer to the arguments
*
*
* When appropriate this function is responsible for inserting
* the reply into the duplicate cache or replaying an existing
* cached reply.
*
* dr_stat reflects the state of the duplicate request that
* has been inserted into or retrieved from the cache
*
* drp is the duplicate request entry
*
*/
int
{
int error = 0;
int dis_flags = 0;
int rv;
/*
* Short circuit the RPC_NULL proc.
*/
return (1);
}
return (0);
}
/* Only NFSv4 Compounds from this point onward */
/*
* Figure out the disposition of the whole COMPOUND
* and record it's IDEMPOTENTCY.
*/
/*
* If NON-IDEMPOTENT then we need to figure out if this
* request can be replied from the duplicate cache.
*
* If this is a new request then we need to insert the
* reply into the duplicate cache.
*/
if (!(dis_flags & RPC_IDEMPOTENT)) {
/* look for a replay from the cache or allocate */
switch (dr_stat) {
case NFS4_DUP_ERROR:
return (1);
/* NOTREACHED */
case NFS4_DUP_PENDING:
/*
* reply has previously been inserted into the
* duplicate cache, however the reply has
* not yet been sent via svc_sendreply()
*/
return (1);
/* NOTREACHED */
case NFS4_DUP_NEW:
/* NON-IDEMPOTENT proc call */
if (rv) /* short ckt sendreply on error */
return (rv);
/*
* dr_res must be initialized before calling
* rfs4_dr_chstate (it frees the reply).
*/
/*
* mark this entry as FREE and plop
* on the end of the cache list
*/
return (1);
}
break;
case NFS4_DUP_REPLAY:
/* replay from the cache */
break;
}
} else {
/* IDEMPOTENT proc call */
if (rv) /* short ckt sendreply on error */
return (rv);
return (1);
}
}
/*
* Send out the replayed reply or the 'real' one.
*/
char *, rbp);
error++;
}
/*
* If this reply was just inserted into the duplicate cache
* or it was replayed from the dup cache; (re)mark it as
* available for replay
*
* At first glance, this 'if' statement seems a little strange;
* testing for NFS4_DUP_REPLAY, and then calling...
*
* rfs4_dr_chatate(NFS4_DUP_REPLAY)
*
* ... but notice that we are checking dr_stat, and not the
* state of the entry itself, the entry will be NFS4_DUP_INUSE,
* we do that so that we know not to prematurely reap it whilst
* we resent it to the client.
*
*/
} else if (dr_stat == NFS4_NOT_DUP) {
}
return (error);
}
{
return (FALSE);
return (FALSE);
/*
* Form a reply tag by copying over the reqeuest tag.
*/
}
return (TRUE);
}
void
{
/*
* Form a reply tag by copying over the request tag.
*/
KM_SLEEP);
/* Any op will do, just need to access status field */
/*
* NFS4ERR_RESOURCE is allowed for all ops, except OP_ILLEGAL.
* Note that all op numbers in the compound array were already
* validated by the XDR decoder (xdr_COMPOUND4args_srv()).
*/
/* compound status is same as first op status */
}
}