nfs4_dispatch.c revision 48a344074403d73a2e38d76ad47299c16c89e0dc
d9ad96c1d1e6612641c338d86699f5700fca7217rg * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d9ad96c1d1e6612641c338d86699f5700fca7217rg * See the License for the specific language governing permissions
d9ad96c1d1e6612641c338d86699f5700fca7217rg * and limitations under the License.
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 * CDDL HEADER END
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Use is subject to license terms.
d9ad96c1d1e6612641c338d86699f5700fca7217rg#pragma ident "%Z%%M% %I% %E% SMI"
d9ad96c1d1e6612641c338d86699f5700fca7217rg * This is the duplicate request cache for NFSv4
d9ad96c1d1e6612641c338d86699f5700fca7217rg * The default size of the duplicate request cache
d9ad96c1d1e6612641c338d86699f5700fca7217rg * The number of buckets we'd like to hash the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * replies into.. do not change this on the fly.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Initialize a duplicate request cache.
48a344074403d73a2e38d76ad47299c16c89e0dcrmestarfs4_init_drc(uint32_t drc_size, uint32_t drc_hash_size)
d9ad96c1d1e6612641c338d86699f5700fca7217rg drc->dr_buckets = kmem_alloc(sizeof (list_t)*drc_hash_size, KM_SLEEP);
d9ad96c1d1e6612641c338d86699f5700fca7217rg list_create(&drc->dr_buckets[bki], sizeof (rfs4_dupreq_t),
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Destroy a duplicate request cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* iterate over the dr_cache and free the enties */
d9ad96c1d1e6612641c338d86699f5700fca7217rg for (drp = list_head(&(drc->dr_cache)); drp != NULL; drp = drp_next) {
d9ad96c1d1e6612641c338d86699f5700fca7217rg * rfs4_dr_chstate:
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Change the state of a rfs4_dupreq. If it's not in transition
d9ad96c1d1e6612641c338d86699f5700fca7217rg * to the FREE state, update the time used and return. If we
d9ad96c1d1e6612641c338d86699f5700fca7217rg * are moving to the FREE state then we need to clean up the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * compound results and move the entry to the end of the list.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Remove entry from the bucket and
d9ad96c1d1e6612641c338d86699f5700fca7217rg * dr_cache list, free compound results.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * rfs4_alloc_dr:
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.
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Have we hit the cache limit yet ?
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * nope, so let's malloc a new one
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta DTRACE_PROBE1(nfss__i__drc_new, rfs4_dupreq_t *, drp);
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Cache is all allocated now traverse the list
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * backwards to find one we can reuse.
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta for (drp_tail = list_tail(&drc->dr_cache); drp_tail != NULL;
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NOTREACHED */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /* grab it. */
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg * rfs4_find_dr:
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Search for an entry in the duplicate request cache by
d9ad96c1d1e6612641c338d86699f5700fca7217rg * calculating the hash index based on the XID, and examining
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the entries in the hash bucket. If we find a match stamp the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * time_used and return. If the entry does not match it could be
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * ready to be freed. Once we have searched the bucket we call
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * rfs4_alloc_dr() to allocate a new entry, or reuse one that is
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * available.
d9ad96c1d1e6612641c338d86699f5700fca7217rgrfs4_find_dr(struct svc_req *req, rfs4_drc_t *drc, rfs4_dupreq_t **dup)
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Get the XID, calculate the bucket and search to
d9ad96c1d1e6612641c338d86699f5700fca7217rg * see if we need to replay from the cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Search the bucket for a matching xid and address.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Found a match so REPLAY the Reply
d9ad96c1d1e6612641c338d86699f5700fca7217rg * This entry must be in transition, so return
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the 'pending' status.
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * Not a match, but maybe this entry is okay
d9ad96c1d1e6612641c338d86699f5700fca7217rg * to be reused.
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 * Init the state to NEW and clear the time used field.
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_time_used.tv_sec = drp->dr_time_used.tv_nsec = 0;
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If needed, resize the address buffer
d9ad96c1d1e6612641c338d86699f5700fca7217rg drp->dr_addr.buf = kmem_alloc(drp->dr_addr.maxlen, KM_NOSLEEP);
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If the malloc fails, mark the entry
d9ad96c1d1e6612641c338d86699f5700fca7217rg * as free and put on the tail.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Copy the address.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Insert at the head of the bucket and
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the drc lists..
d9ad96c1d1e6612641c338d86699f5700fca7217rg * This function handles the duplicate request cache,
d9ad96c1d1e6612641c338d86699f5700fca7217rg * NULL_PROC and COMPOUND procedure calls for NFSv4;
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Passed into this function are:-
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 * When appropriate this function is responsible for inserting
d9ad96c1d1e6612641c338d86699f5700fca7217rg * the reply into the duplicate cache or replaying an existing
d9ad96c1d1e6612641c338d86699f5700fca7217rg * cached reply.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * dr_stat reflects the state of the duplicate request that
d9ad96c1d1e6612641c338d86699f5700fca7217rg * has been inserted into or retrieved from the cache
d9ad96c1d1e6612641c338d86699f5700fca7217rg * drp is the duplicate request entry
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Short circuit the RPC_NULL proc.
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (0);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* Only NFSv4 Compounds from this point onward */
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Figure out the disposition of the whole COMPOUND
d9ad96c1d1e6612641c338d86699f5700fca7217rg * and record it's IDEMPOTENTCY.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If NON-IDEMPOTENT then we need to figure out if this
d9ad96c1d1e6612641c338d86699f5700fca7217rg * request can be replied from the duplicate cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg * If this is a new request then we need to insert the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * reply into the duplicate cache.
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* look for a replay from the cache or allocate */
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg * reply has previously been inserted into the
d9ad96c1d1e6612641c338d86699f5700fca7217rg * duplicate cache, however the reply has
d9ad96c1d1e6612641c338d86699f5700fca7217rg * not yet been sent via svc_sendreply()
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NOTREACHED */
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* NON-IDEMPOTENT proc call */
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith * dr_res must be initialized before calling
3f720b33ddd72eec6da368eaaa751ed3acbca723jasmith * rfs4_dr_chstate (it frees the reply).
d9ad96c1d1e6612641c338d86699f5700fca7217rg * mark this entry as FREE and plop
d9ad96c1d1e6612641c338d86699f5700fca7217rg * on the end of the cache list
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* replay from the cache */
d9ad96c1d1e6612641c338d86699f5700fca7217rg /* IDEMPOTENT proc call */
d9ad96c1d1e6612641c338d86699f5700fca7217rg return (1);
d9ad96c1d1e6612641c338d86699f5700fca7217rg * Send out the replayed reply or the 'real' one.
7c46fb7fef68117215a0c60a64149aaea1a38578ek if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)rbp)) {
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 * At first glance, this 'if' statement seems a little strange;
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * testing for NFS4_DUP_REPLAY, and then calling...
48a344074403d73a2e38d76ad47299c16c89e0dcrmesta * rfs4_dr_chatate(NFS4_DUP_REPLAY)
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.