nfs4_dispatch.c revision 3f720b33ddd72eec6da368eaaa751ed3acbca723
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * CDDL HEADER START
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner * The contents of this file are subject to the terms of the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Common Development and Distribution License, Version 1.0 only
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * (the "License"). You may not use this file except in compliance
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * with the License.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * or http://www.opensolaris.org/os/licensing.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * See the License for the specific language governing permissions
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and limitations under the License.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * When distributing Covered Code, include this CDDL HEADER in each
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If applicable, add the following below this CDDL HEADER, with the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * fields enclosed by brackets "[]" replaced with your own identifying
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * information: Portions Copyright [yyyy] [name of copyright owner]
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * CDDL HEADER END
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Use is subject to license terms.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#pragma ident "%Z%%M% %I% %E% SMI"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/systm.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/sdt.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <rpc/types.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <rpc/auth.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <rpc/auth_unix.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <rpc/auth_des.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <rpc/svc.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <rpc/xdr.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <nfs/nfs4.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <nfs/nfs_dispatch.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <nfs/nfs4_drc.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This is the duplicate request cache for NFSv4
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_drc_t *nfs4_drc = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * How long the entry can remain in the cache
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * once it has been sent to the client and not
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * used in a reply (in seconds)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinunsigned nfs4_drc_lifetime = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The default size of the duplicate request cache
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinuint32_t nfs4_drc_max = 8 * 1024;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The number of buckets we'd like to hash the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * replies into.. do not change this on the fly.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinuint32_t nfs4_drc_hash = 541;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Initialize a duplicate request cache.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_drc_t *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_init_drc(uint32_t drc_size, uint32_t drc_hash_size, unsigned ttl)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_drc_t *drc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint32_t bki;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drc_size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drc_hash_size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc = kmem_alloc(sizeof (rfs4_drc_t), KM_SLEEP);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc->max_size = drc_size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc->in_use = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc->drc_ttl = ttl;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_init(&drc->lock, NULL, MUTEX_DEFAULT, NULL);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc->dr_hash = drc_hash_size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc->dr_buckets = kmem_alloc(sizeof (list_t)*drc_hash_size, KM_SLEEP);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (bki = 0; bki < drc_hash_size; bki++) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_create(&drc->dr_buckets[bki], sizeof (rfs4_dupreq_t),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin offsetof(rfs4_dupreq_t, dr_bkt_next));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_create(&(drc->dr_cache), sizeof (rfs4_dupreq_t),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin offsetof(rfs4_dupreq_t, dr_next));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (drc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Destroy a duplicate request cache.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_fini_drc(rfs4_drc_t *drc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *drp, *drp_next;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* iterate over the dr_cache and free the enties */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (drp = list_head(&(drc->dr_cache)); drp != NULL; drp = drp_next) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_state == NFS4_DUP_REPLAY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_compound_free(&(drp->dr_res));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_addr.buf != NULL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp_next = list_next(&(drc->dr_cache), drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin kmem_free(drp, sizeof (rfs4_dupreq_t));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_destroy(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin kmem_free(drc->dr_buckets,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sizeof (list_t)*drc->dr_hash);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin kmem_free(drc, sizeof (rfs4_drc_t));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * rfs4_dr_chstate:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Change the state of a rfs4_dupreq. If it's not in transition
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to the FREE state, update the time used and return. If we
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * are moving to the FREE state then we need to clean up the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compound results and move the entry to the end of the list.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_dr_chstate(rfs4_dupreq_t *drp, int new_state)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_drc_t *drc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drp->drc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drp->dr_bkt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(MUTEX_HELD(&drp->drc->lock));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_state = new_state;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (new_state != NFS4_DUP_FREE) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin gethrestime(&drp->dr_time_used);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc = drp->drc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Remove entry from the bucket and
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * dr_cache list, free compound results.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_remove(drp->dr_bkt, drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_remove(&(drc->dr_cache), drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_compound_free(&(drp->dr_res));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * rfs4_alloc_dr:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Pick an entry off the tail -- Use if it is
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * marked NFS4_DUP_FREE, or is an entry in the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * NFS4_DUP_REPLAY state that has timed-out...
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Otherwise malloc a new one if we have not reached
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * our maximum cache limit.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The list should be in time order, so no need
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to traverse backwards looking for a timed out
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * entry, NFS4_DUP_FREE's are place on the tail.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_dupreq_t *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_alloc_dr(rfs4_drc_t *drc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *drp_tail, *drp = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(drc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(MUTEX_HELD(&drc->lock));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((drp_tail = list_tail(&drc->dr_cache)) != NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (drp_tail->dr_state) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case NFS4_DUP_FREE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_remove(&(drc->dr_cache), drp_tail);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE1(nfss__i__drc_freeclaim,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *, drp_tail);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (drp_tail);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* NOTREACHED */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case NFS4_DUP_REPLAY:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (gethrestime_sec() >
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp_tail->dr_time_used.tv_sec+drc->drc_ttl) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* this entry has timedout so grab it. */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin rfs4_dr_chstate(drp_tail, NFS4_DUP_FREE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE1(nfss__i__drc_ttlclaim,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *, drp_tail);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (drp_tail);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Didn't find something to recycle have
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * we hit the cache limit ?
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drc->in_use >= drc->max_size) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE1(nfss__i__drc_full,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_drc_t *, drc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (NULL);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* nope, so let's malloc a new one */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp = kmem_zalloc(sizeof (rfs4_dupreq_t), KM_SLEEP);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->drc = drc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drc->in_use++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin gethrestime(&drp->dr_time_created);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE1(nfss__i__drc_new, rfs4_dupreq_t *, drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * rfs4_find_dr:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Search for an entry in the duplicate request cache by
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * calculating the hash index based on the XID, and examining
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the entries in the hash bucket. If we find a match stamp the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * time_used and return. If the entry does not match it could be
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * ready to be freed. Once we have searched the bucket and we
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * have not exhausted the maximum limit for the cache we will
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * allocate a new entry.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_find_dr(struct svc_req *req, rfs4_drc_t *drc, rfs4_dupreq_t **dup)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint32_t the_xid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_t *dr_bkt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *drp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int bktdex;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Get the XID, calculate the bucket and search to
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * see if we need to replay from the cache.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin the_xid = req->rq_xprt->xp_xid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bktdex = the_xid % drc->dr_hash;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dr_bkt = (list_t *)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin &(drc->dr_buckets[(the_xid % drc->dr_hash)]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE3(nfss__i__drc_bktdex,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int, bktdex,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint32_t, the_xid,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_t *, dr_bkt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *dup = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mutex_enter(&drc->lock);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /*
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * Search the bucket for a matching xid and address.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (drp = list_head(dr_bkt); drp != NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp = list_next(dr_bkt, drp)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_xid == the_xid &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.len == req->rq_xprt->xp_rtaddr.len &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bcmp((caddr_t)drp->dr_addr.buf,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (caddr_t)req->rq_xprt->xp_rtaddr.buf,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.len) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Found a match so REPLAY the Reply
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_state == NFS4_DUP_REPLAY) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin gethrestime(&drp->dr_time_used);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *dup = drp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE1(nfss__i__drc_replay,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *, drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (NFS4_DUP_REPLAY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This entry must be in transition, so return
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the 'pending' status.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (NFS4_DUP_PENDING);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Not a match, but maybe this entry is ready
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to be reused.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_state == NFS4_DUP_REPLAY &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (gethrestime_sec() >
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_time_used.tv_sec+drc->drc_ttl)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dr_chstate(drp, NFS4_DUP_FREE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_insert_tail(&(drp->drc->dr_cache), drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp = rfs4_alloc_dr(drc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (NFS4_DUP_ERROR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Place at the head of the list, init the state
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * to NEW and clear the time used field.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_state = NFS4_DUP_NEW;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_time_used.tv_sec = drp->dr_time_used.tv_nsec = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If needed, resize the address buffer
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_addr.maxlen < req->rq_xprt->xp_rtaddr.len) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_addr.buf != NULL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.maxlen = req->rq_xprt->xp_rtaddr.len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.buf = kmem_alloc(drp->dr_addr.maxlen, KM_NOSLEEP);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (drp->dr_addr.buf == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If the malloc fails, mark the entry
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * as free and put on the tail.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.maxlen = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_state = NFS4_DUP_FREE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_insert_tail(&(drc->dr_cache), drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (NFS4_DUP_ERROR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Copy the address.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.len = req->rq_xprt->xp_rtaddr.len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bcopy((caddr_t)req->rq_xprt->xp_rtaddr.buf,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (caddr_t)drp->dr_addr.buf,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_addr.len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_xid = the_xid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_bkt = dr_bkt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Insert at the head of the bucket and
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the drc lists..
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_insert_head(&drc->dr_cache, drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_insert_head(dr_bkt, drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drc->lock);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *dup = drp;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (NFS4_DUP_NEW);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This function handles the duplicate request cache,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * NULL_PROC and COMPOUND procedure calls for NFSv4;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Passed into this function are:-
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * disp A pointer to our dispatch table entry
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * req The request to process
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * xprt The server transport handle
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * ap A pointer to the arguments
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * When appropriate this function is responsible for inserting
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the reply into the duplicate cache or replaying an existing
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * cached reply.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * dr_stat reflects the state of the duplicate request that
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * has been inserted into or retrieved from the cache
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * drp is the duplicate request entry
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinrfs4_dispatch(struct rpcdisp *disp, struct svc_req *req,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin SVCXPRT *xprt, char *ap)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin COMPOUND4res res_buf, *rbp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin COMPOUND4args *cap;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cred_t *cr = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int error = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int dis_flags = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int dr_stat = NFS4_NOT_DUP;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dupreq_t *drp = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(disp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Short circuit the RPC_NULL proc.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (disp->dis_proc == rpc_null) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!svc_sendreply(xprt, xdr_void, NULL)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Only NFSv4 Compounds from this point onward */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rbp = &res_buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cap = (COMPOUND4args *)ap;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Figure out the disposition of the whole COMPOUND
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * and record it's IDEMPOTENTCY.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_compound_flagproc(cap, &dis_flags);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If NON-IDEMPOTENT then we need to figure out if this
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * request can be replied from the duplicate cache.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * If this is a new request then we need to insert the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * reply into the duplicate cache.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(dis_flags & RPC_IDEMPOTENT)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* look for a replay from the cache or allocate */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dr_stat = rfs4_find_dr(req, nfs4_drc, &drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (dr_stat) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case NFS4_DUP_ERROR:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin svcerr_systemerr(xprt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* NOTREACHED */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case NFS4_DUP_PENDING:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * reply has previously been inserted into the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * duplicate cache, however the reply has
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * not yet been sent via svc_sendreply()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* NOTREACHED */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case NFS4_DUP_NEW:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_flag |= T_DONTPEND;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* NON-IDEMPOTENT proc call */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_compound(cap, rbp, NULL, req, cr);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_flag &= ~T_DONTPEND;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * dr_res must be initialized before calling
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * rfs4_dr_chstate (it frees the reply).
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin drp->dr_res = res_buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (curthread->t_flag & T_WOULDBLOCK) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_flag &= ~T_WOULDBLOCK;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * mark this entry as FREE and plop
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * on the end of the cache list
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&drp->drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dr_chstate(drp, NFS4_DUP_FREE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin list_insert_tail(&(drp->drc->dr_cache), drp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drp->drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case NFS4_DUP_REPLAY:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* replay from the cache */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rbp = &(drp->dr_res);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_flag |= T_DONTPEND;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* IDEMPOTENT proc call */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_compound(cap, rbp, NULL, req, cr);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_flag &= ~T_DONTPEND;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (curthread->t_flag & T_WOULDBLOCK) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_flag &= ~T_WOULDBLOCK;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Send out the replayed reply or the 'real' one.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin DTRACE_PROBE2(nfss__e__dispatch_sendfail,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct svc_req *, xprt,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *, rbp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If this reply was just inserted into the duplicate cache
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * mark it as available for replay
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (dr_stat == NFS4_DUP_NEW) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&drp->drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_dr_chstate(drp, NFS4_DUP_REPLAY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&drp->drc->lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else if (dr_stat == NFS4_NOT_DUP) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rfs4_compound_free(rbp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (error);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin