d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * CDDL HEADER START
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * The contents of this file are subject to the terms of the
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Common Development and Distribution License (the "License").
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * You may not use this file except in compliance with the License.
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d9ad96c1d1e6612641c338d86699f5700fca7217rg * or http://www.opensolaris.org/os/licensing.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * See the License for the specific language governing permissions
d9ad96c1d1e6612641c338d86699f5700fca7217rg * and limitations under the License.
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * When distributing Covered Code, include this CDDL HEADER in each
d9ad96c1d1e6612641c338d86699f5700fca7217rg * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If applicable, add the following below this CDDL HEADER, with the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * fields enclosed by brackets "[]" replaced with your own identifying
d9ad96c1d1e6612641c338d86699f5700fca7217rg * information: Portions Copyright [yyyy] [name of copyright owner]
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * CDDL HEADER END
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Use is subject to license terms.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg
6cb014625d9459c150e9e75ed2b8a5d06b5b6137rg#include <sys/systm.h>
6cb014625d9459c150e9e75ed2b8a5d06b5b6137rg#include <sys/sdt.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <rpc/types.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <rpc/auth.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <rpc/auth_unix.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <rpc/auth_des.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <rpc/svc.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <rpc/xdr.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <nfs/nfs4.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <nfs/nfs_dispatch.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg#include <nfs/nfs4_drc.h>
d9ad96c1d1e6612641c338d86699f5700fca7217rg
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs#define NFS4_MAX_MINOR_VERSION 0
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * This is the duplicate request cache for NFSv4
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_drc_t *nfs4_drc = NULL;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * The default size of the duplicate request cache
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rguint32_t nfs4_drc_max = 8 * 1024;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * The number of buckets we'd like to hash the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * replies into.. do not change this on the fly.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rguint32_t nfs4_drc_hash = 541;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngostatic void rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Initialize a duplicate request cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_drc_t *
48a344074403d73a2e38d76ad47299c16c89e0dcrmestarfs4_init_drc(uint32_t drc_size, uint32_t drc_hash_size)
d9ad96c1d1e6612641c338d86699f5700fca7217rg{
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_drc_t *drc;
d9ad96c1d1e6612641c338d86699f5700fca7217rg uint32_t bki;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drc_size);
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drc_hash_size);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc = kmem_alloc(sizeof (rfs4_drc_t), KM_SLEEP);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc->max_size = drc_size;
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc->in_use = 0;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_init(&drc->lock, NULL, MUTEX_DEFAULT, NULL);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc->dr_hash = drc_hash_size;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc->dr_buckets = kmem_alloc(sizeof (list_t)*drc_hash_size, KM_SLEEP);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg for (bki = 0; bki < drc_hash_size; bki++) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_create(&drc->dr_buckets[bki], sizeof (rfs4_dupreq_t),
d9ad96c1d1e6612641c338d86699f5700fca7217rg offsetof(rfs4_dupreq_t, dr_bkt_next));
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_create(&(drc->dr_cache), sizeof (rfs4_dupreq_t),
f3b585ce799a83688c5532c430f6133f098431c2samf offsetof(rfs4_dupreq_t, dr_next));
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (drc);
d9ad96c1d1e6612641c338d86699f5700fca7217rg}
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Destroy a duplicate request cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgvoid
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_fini_drc(rfs4_drc_t *drc)
d9ad96c1d1e6612641c338d86699f5700fca7217rg{
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_dupreq_t *drp, *drp_next;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drc);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* iterate over the dr_cache and free the enties */
d9ad96c1d1e6612641c338d86699f5700fca7217rg for (drp = list_head(&(drc->dr_cache)); drp != NULL; drp = drp_next) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_state == NFS4_DUP_REPLAY)
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_compound_free(&(drp->dr_res));
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_addr.buf != NULL)
d9ad96c1d1e6612641c338d86699f5700fca7217rg kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp_next = list_next(&(drc->dr_cache), drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg kmem_free(drp, sizeof (rfs4_dupreq_t));
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_destroy(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg kmem_free(drc->dr_buckets,
f3b585ce799a83688c5532c430f6133f098431c2samf sizeof (list_t)*drc->dr_hash);
d9ad96c1d1e6612641c338d86699f5700fca7217rg kmem_free(drc, sizeof (rfs4_drc_t));
d9ad96c1d1e6612641c338d86699f5700fca7217rg}
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * rfs4_dr_chstate:
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Change the state of a rfs4_dupreq. If it's not in transition
b44672165bacece424461fb91f365ba590c50426pf * to the FREE state, return. If we are moving to the FREE state
b44672165bacece424461fb91f365ba590c50426pf * then we need to clean up the compound results and move the entry
b44672165bacece424461fb91f365ba590c50426pf * to the end of the list.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgvoid
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_dr_chstate(rfs4_dupreq_t *drp, int new_state)
d9ad96c1d1e6612641c338d86699f5700fca7217rg{
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_drc_t *drc;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drp->drc);
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drp->dr_bkt);
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(MUTEX_HELD(&drp->drc->lock));
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_state = new_state;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
b44672165bacece424461fb91f365ba590c50426pf if (new_state != NFS4_DUP_FREE)
d9ad96c1d1e6612641c338d86699f5700fca7217rg return;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc = drp->drc;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Remove entry from the bucket and
d9ad96c1d1e6612641c338d86699f5700fca7217rg * dr_cache list, free compound results.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_remove(drp->dr_bkt, drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_remove(&(drc->dr_cache), drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_compound_free(&(drp->dr_res));
d9ad96c1d1e6612641c338d86699f5700fca7217rg}
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * rfs4_alloc_dr:
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Malloc a new one if we have not reached our maximum cache
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * limit, otherwise pick an entry off the tail -- Use if it
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * is marked as NFS4_DUP_FREE, or is an entry in the
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * NFS4_DUP_REPLAY state.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_dupreq_t *
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_alloc_dr(rfs4_drc_t *drc)
d9ad96c1d1e6612641c338d86699f5700fca7217rg{
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_dupreq_t *drp_tail, *drp = NULL;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(drc);
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(MUTEX_HELD(&drc->lock));
d9ad96c1d1e6612641c338d86699f5700fca7217rg
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /*
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Have we hit the cache limit yet ?
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta if (drc->in_use < drc->max_size) {
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /*
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * nope, so let's malloc a new one
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta drp = kmem_zalloc(sizeof (rfs4_dupreq_t), KM_SLEEP);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta drp->drc = drc;
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta drc->in_use++;
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta DTRACE_PROBE1(nfss__i__drc_new, rfs4_dupreq_t *, drp);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta return (drp);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta }
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /*
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Cache is all allocated now traverse the list
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * backwards to find one we can reuse.
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta for (drp_tail = list_tail(&drc->dr_cache); drp_tail != NULL;
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta drp_tail = list_prev(&drc->dr_cache, drp_tail)) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg switch (drp_tail->dr_state) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg case NFS4_DUP_FREE:
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_remove(&(drc->dr_cache), drp_tail);
d9ad96c1d1e6612641c338d86699f5700fca7217rg DTRACE_PROBE1(nfss__i__drc_freeclaim,
f3b585ce799a83688c5532c430f6133f098431c2samf rfs4_dupreq_t *, drp_tail);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (drp_tail);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg case NFS4_DUP_REPLAY:
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /* grab it. */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta rfs4_dr_chstate(drp_tail, NFS4_DUP_FREE);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta DTRACE_PROBE1(nfss__i__drc_replayclaim,
f3b585ce799a83688c5532c430f6133f098431c2samf rfs4_dupreq_t *, drp_tail);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta return (drp_tail);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta DTRACE_PROBE1(nfss__i__drc_full, rfs4_drc_t *, drc);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta return (NULL);
d9ad96c1d1e6612641c338d86699f5700fca7217rg}
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * rfs4_find_dr:
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Search for an entry in the duplicate request cache by
d9ad96c1d1e6612641c338d86699f5700fca7217rg * calculating the hash index based on the XID, and examining
b44672165bacece424461fb91f365ba590c50426pf * the entries in the hash bucket. If we find a match, return.
b44672165bacece424461fb91f365ba590c50426pf * Once we have searched the bucket we call rfs4_alloc_dr() to
b44672165bacece424461fb91f365ba590c50426pf * allocate a new entry, or reuse one that is available.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgint
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_find_dr(struct svc_req *req, rfs4_drc_t *drc, rfs4_dupreq_t **dup)
d9ad96c1d1e6612641c338d86699f5700fca7217rg{
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg uint32_t the_xid;
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_t *dr_bkt;
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_dupreq_t *drp;
d9ad96c1d1e6612641c338d86699f5700fca7217rg int bktdex;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Get the XID, calculate the bucket and search to
d9ad96c1d1e6612641c338d86699f5700fca7217rg * see if we need to replay from the cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg the_xid = req->rq_xprt->xp_xid;
d9ad96c1d1e6612641c338d86699f5700fca7217rg bktdex = the_xid % drc->dr_hash;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg dr_bkt = (list_t *)
f3b585ce799a83688c5532c430f6133f098431c2samf &(drc->dr_buckets[(the_xid % drc->dr_hash)]);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg DTRACE_PROBE3(nfss__i__drc_bktdex,
f3b585ce799a83688c5532c430f6133f098431c2samf int, bktdex,
f3b585ce799a83688c5532c430f6133f098431c2samf uint32_t, the_xid,
f3b585ce799a83688c5532c430f6133f098431c2samf list_t *, dr_bkt);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg *dup = NULL;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_enter(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Search the bucket for a matching xid and address.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg for (drp = list_head(dr_bkt); drp != NULL;
f3b585ce799a83688c5532c430f6133f098431c2samf drp = list_next(dr_bkt, drp)) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_xid == the_xid &&
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.len == req->rq_xprt->xp_rtaddr.len &&
d9ad96c1d1e6612641c338d86699f5700fca7217rg bcmp((caddr_t)drp->dr_addr.buf,
d9ad96c1d1e6612641c338d86699f5700fca7217rg (caddr_t)req->rq_xprt->xp_rtaddr.buf,
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.len) == 0) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Found a match so REPLAY the Reply
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_state == NFS4_DUP_REPLAY) {
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta rfs4_dr_chstate(drp, NFS4_DUP_INUSE);
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg *dup = drp;
d9ad96c1d1e6612641c338d86699f5700fca7217rg DTRACE_PROBE1(nfss__i__drc_replay,
f3b585ce799a83688c5532c430f6133f098431c2samf rfs4_dupreq_t *, drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (NFS4_DUP_REPLAY);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * This entry must be in transition, so return
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the 'pending' status.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (NFS4_DUP_PENDING);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp = rfs4_alloc_dr(drc);
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /*
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * The DRC is full and all entries are in use. Upper function
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * should error out this request and force the client to
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * retransmit -- effectively this is a resource issue. NFSD
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * threads tied up with native File System, or the cache size
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * is too small for the server load.
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta if (drp == NULL)
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (NFS4_DUP_ERROR);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
b44672165bacece424461fb91f365ba590c50426pf * Init the state to NEW.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_state = NFS4_DUP_NEW;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If needed, resize the address buffer
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_addr.maxlen < req->rq_xprt->xp_rtaddr.len) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_addr.buf != NULL)
d9ad96c1d1e6612641c338d86699f5700fca7217rg kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.maxlen = req->rq_xprt->xp_rtaddr.len;
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.buf = kmem_alloc(drp->dr_addr.maxlen, KM_NOSLEEP);
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (drp->dr_addr.buf == NULL) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If the malloc fails, mark the entry
d9ad96c1d1e6612641c338d86699f5700fca7217rg * as free and put on the tail.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.maxlen = 0;
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_state = NFS4_DUP_FREE;
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_enter(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_insert_tail(&(drc->dr_cache), drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (NFS4_DUP_ERROR);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Copy the address.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.len = req->rq_xprt->xp_rtaddr.len;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg bcopy((caddr_t)req->rq_xprt->xp_rtaddr.buf,
f3b585ce799a83688c5532c430f6133f098431c2samf (caddr_t)drp->dr_addr.buf,
f3b585ce799a83688c5532c430f6133f098431c2samf drp->dr_addr.len);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_xid = the_xid;
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_bkt = dr_bkt;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Insert at the head of the bucket and
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the drc lists..
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_enter(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_insert_head(&drc->dr_cache, drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_insert_head(dr_bkt, drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg *dup = drp;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (NFS4_DUP_NEW);
d9ad96c1d1e6612641c338d86699f5700fca7217rg}
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg/*
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * This function handles the duplicate request cache,
d9ad96c1d1e6612641c338d86699f5700fca7217rg * NULL_PROC and COMPOUND procedure calls for NFSv4;
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Passed into this function are:-
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * disp A pointer to our dispatch table entry
d9ad96c1d1e6612641c338d86699f5700fca7217rg * req The request to process
d9ad96c1d1e6612641c338d86699f5700fca7217rg * xprt The server transport handle
d9ad96c1d1e6612641c338d86699f5700fca7217rg * ap A pointer to the arguments
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * When appropriate this function is responsible for inserting
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the reply into the duplicate cache or replaying an existing
d9ad96c1d1e6612641c338d86699f5700fca7217rg * cached reply.
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * dr_stat reflects the state of the duplicate request that
d9ad96c1d1e6612641c338d86699f5700fca7217rg * has been inserted into or retrieved from the cache
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * drp is the duplicate request entry
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rgint
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_dispatch(struct rpcdisp *disp, struct svc_req *req,
f7877f5d39900cfd8b20dd673e5ccc1ef7cc7447Dan McDonald SVCXPRT *xprt, char *ap)
d9ad96c1d1e6612641c338d86699f5700fca7217rg{
d9ad96c1d1e6612641c338d86699f5700fca7217rg
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta COMPOUND4res res_buf;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta COMPOUND4res *rbp;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta COMPOUND4args *cap;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta cred_t *cr = NULL;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta int error = 0;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta int dis_flags = 0;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta int dr_stat = NFS4_NOT_DUP;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta rfs4_dupreq_t *drp = NULL;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta int rv;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg ASSERT(disp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Short circuit the RPC_NULL proc.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (disp->dis_proc == rpc_null) {
f3b585ce799a83688c5532c430f6133f098431c2samf DTRACE_NFSV4_1(null__start, struct svc_req *, req);
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (!svc_sendreply(xprt, xdr_void, NULL)) {
f3b585ce799a83688c5532c430f6133f098431c2samf DTRACE_NFSV4_1(null__done, struct svc_req *, req);
71c6e709ab02e1f073342b9c7256170eae3833b0rmesta svcerr_systemerr(xprt);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
f3b585ce799a83688c5532c430f6133f098431c2samf DTRACE_NFSV4_1(null__done, struct svc_req *, req);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (0);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* Only NFSv4 Compounds from this point onward */
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg rbp = &res_buf;
d9ad96c1d1e6612641c338d86699f5700fca7217rg cap = (COMPOUND4args *)ap;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Figure out the disposition of the whole COMPOUND
d9ad96c1d1e6612641c338d86699f5700fca7217rg * and record it's IDEMPOTENTCY.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_compound_flagproc(cap, &dis_flags);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If NON-IDEMPOTENT then we need to figure out if this
d9ad96c1d1e6612641c338d86699f5700fca7217rg * request can be replied from the duplicate cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg *
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If this is a new request then we need to insert the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * reply into the duplicate cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (!(dis_flags & RPC_IDEMPOTENT)) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* look for a replay from the cache or allocate */
d9ad96c1d1e6612641c338d86699f5700fca7217rg dr_stat = rfs4_find_dr(req, nfs4_drc, &drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg switch (dr_stat) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg case NFS4_DUP_ERROR:
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rfs4_resource_err(req, cap);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg case NFS4_DUP_PENDING:
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * reply has previously been inserted into the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * duplicate cache, however the reply has
d9ad96c1d1e6612641c338d86699f5700fca7217rg * not yet been sent via svc_sendreply()
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg case NFS4_DUP_NEW:
d9ad96c1d1e6612641c338d86699f5700fca7217rg curthread->t_flag |= T_DONTPEND;
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NON-IDEMPOTENT proc call */
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta rfs4_compound(cap, rbp, NULL, req, cr, &rv);
d9ad96c1d1e6612641c338d86699f5700fca7217rg curthread->t_flag &= ~T_DONTPEND;
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta if (rv) /* short ckt sendreply on error */
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta return (rv);
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith /*
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith * dr_res must be initialized before calling
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith * rfs4_dr_chstate (it frees the reply).
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith */
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith drp->dr_res = res_buf;
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (curthread->t_flag & T_WOULDBLOCK) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg curthread->t_flag &= ~T_WOULDBLOCK;
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * mark this entry as FREE and plop
d9ad96c1d1e6612641c338d86699f5700fca7217rg * on the end of the cache list
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_enter(&drp->drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_dr_chstate(drp, NFS4_DUP_FREE);
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_insert_tail(&(drp->drc->dr_cache), drp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drp->drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg break;
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg case NFS4_DUP_REPLAY:
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* replay from the cache */
d9ad96c1d1e6612641c338d86699f5700fca7217rg rbp = &(drp->dr_res);
d9ad96c1d1e6612641c338d86699f5700fca7217rg break;
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg } else {
d9ad96c1d1e6612641c338d86699f5700fca7217rg curthread->t_flag |= T_DONTPEND;
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* IDEMPOTENT proc call */
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta rfs4_compound(cap, rbp, NULL, req, cr, &rv);
d9ad96c1d1e6612641c338d86699f5700fca7217rg curthread->t_flag &= ~T_DONTPEND;
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta if (rv) /* short ckt sendreply on error */
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta return (rv);
2e9d26a4f1e604a24aaa3e3694c829ba2ff9fbe9rmesta
d9ad96c1d1e6612641c338d86699f5700fca7217rg if (curthread->t_flag & T_WOULDBLOCK) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg curthread->t_flag &= ~T_WOULDBLOCK;
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Send out the replayed reply or the 'real' one.
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
f7877f5d39900cfd8b20dd673e5ccc1ef7cc7447Dan McDonald if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg DTRACE_PROBE2(nfss__e__dispatch_sendfail,
f3b585ce799a83688c5532c430f6133f098431c2samf struct svc_req *, xprt,
f3b585ce799a83688c5532c430f6133f098431c2samf char *, rbp);
71c6e709ab02e1f073342b9c7256170eae3833b0rmesta svcerr_systemerr(xprt);
d9ad96c1d1e6612641c338d86699f5700fca7217rg error++;
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg /*
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If this reply was just inserted into the duplicate cache
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * or it was replayed from the dup cache; (re)mark it as
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * available for replay
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta *
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * At first glance, this 'if' statement seems a little strange;
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * testing for NFS4_DUP_REPLAY, and then calling...
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta *
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * rfs4_dr_chatate(NFS4_DUP_REPLAY)
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta *
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * ... but notice that we are checking dr_stat, and not the
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * state of the entry itself, the entry will be NFS4_DUP_INUSE,
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * we do that so that we know not to prematurely reap it whilst
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * we resent it to the client.
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta *
d9ad96c1d1e6612641c338d86699f5700fca7217rg */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta if (dr_stat == NFS4_DUP_NEW || dr_stat == NFS4_DUP_REPLAY) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_enter(&drp->drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_dr_chstate(drp, NFS4_DUP_REPLAY);
d9ad96c1d1e6612641c338d86699f5700fca7217rg mutex_exit(&drp->drc->lock);
d9ad96c1d1e6612641c338d86699f5700fca7217rg } else if (dr_stat == NFS4_NOT_DUP) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg rfs4_compound_free(rbp);
d9ad96c1d1e6612641c338d86699f5700fca7217rg }
d9ad96c1d1e6612641c338d86699f5700fca7217rg
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (error);
d9ad96c1d1e6612641c338d86699f5700fca7217rg}
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvsbool_t
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvsrfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs{
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs COMPOUND4args *argsp;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs COMPOUND4res res_buf, *resp;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs if (req->rq_vers != 4)
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs return (FALSE);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs argsp = (COMPOUND4args *)args;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION)
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs return (FALSE);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp = &res_buf;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs /*
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs * Form a reply tag by copying over the reqeuest tag.
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs */
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp->tag.utf8string_val =
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp->tag.utf8string_len = argsp->tag.utf8string_len;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs bcopy(argsp->tag.utf8string_val, resp->tag.utf8string_val,
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp->tag.utf8string_len);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp->array_len = 0;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp->array = NULL;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)resp)) {
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs DTRACE_PROBE2(nfss__e__minorvers_mismatch,
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs SVCXPRT *, xprt, char *, resp);
71c6e709ab02e1f073342b9c7256170eae3833b0rmesta svcerr_systemerr(xprt);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs }
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs rfs4_compound_free(resp);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs return (TRUE);
7d12f3bc086bd094c3bf327e7bd04f94701e1c69maheshvs}
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngovoid
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngorfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp)
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo{
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo COMPOUND4res res_buf, *rbp;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo nfs_resop4 *resop;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo PUTFH4res *resp;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp = &res_buf;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo /*
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo * Form a reply tag by copying over the request tag.
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo */
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp->tag.utf8string_val =
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp->tag.utf8string_len = argsp->tag.utf8string_len;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo bcopy(argsp->tag.utf8string_val, rbp->tag.utf8string_val,
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp->tag.utf8string_len);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp->array_len = 1;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp->array = kmem_zalloc(rbp->array_len * sizeof (nfs_resop4),
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo KM_SLEEP);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo resop = &rbp->array[0];
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo resop->resop = argsp->array[0].argop; /* copy first op over */
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo /* Any op will do, just need to access status field */
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo resp = &resop->nfs_resop4_u.opputfh;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo /*
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo * NFS4ERR_RESOURCE is allowed for all ops, except OP_ILLEGAL.
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo * Note that all op numbers in the compound array were already
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo * validated by the XDR decoder (xdr_COMPOUND4args_srv()).
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo */
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo resp->status = (resop->resop == OP_ILLEGAL ?
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo NFS4ERR_OP_ILLEGAL : NFS4ERR_RESOURCE);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo /* compound status is same as first op status */
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo rbp->status = resp->status;
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo if (!svc_sendreply(req->rq_xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo DTRACE_PROBE2(nfss__rsrc_err__sendfail,
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo struct svc_req *, req->rq_xprt, char *, rbp);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo svcerr_systemerr(req->rq_xprt);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo }
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo UTF8STRING_FREE(rbp->tag);
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo kmem_free(rbp->array, rbp->array_len * sizeof (nfs_resop4));
67e4138c8e3ce16b926a032b00d85cdf827f4dc6Dai Ngo}