/** * @brief Copy a operation into a state owner * * This is only used for NFSv4.0 and only for a specific subset of * operations for which it guarantees At-Most Once Semantics. * * @param[in,out] owner The owner to hold the operation * @param[in] seqid Seqid of this operation * @param[in] args Arguments of operation to copy * @param[in] data Compound data * @param[in] resp Response to copy * @param[in] tag Arbitrary string for logging/debugging */ void Copy_nfs4_state_req(state_owner_t *owner, seqid4 seqid, nfs_argop4 *args, cache_entry_t *entry, nfs_resop4 *resp, const char *tag) { /* Simplify use of this function when we may not be keeping any data for the * state owner */ if(owner == NULL) return; LogFullDebug(COMPONENT_STATE, "%s: saving response %p so_seqid %u new seqid %u", tag, owner, owner->so_owner.so_nfs4_owner.so_seqid, seqid); /* Free previous response */ nfs4_Compound_FreeOne(&owner->so_owner.so_nfs4_owner.so_resp); /* Copy new response */ nfs4_Compound_CopyResOne(&owner->so_owner.so_nfs4_owner.so_resp, resp); /* Deep copy OPEN args? */ if(owner->so_owner.so_nfs4_owner.so_args.argop == NFS4_OP_OPEN) { } /* Copy bnew args */ memcpy(&owner->so_owner.so_nfs4_owner.so_args, args, sizeof(owner->so_owner.so_nfs4_owner.so_args)); /* Copy new file, note we don't take any reference, so this entry * might not remain valid, but the pointer value suffices here. */ owner->so_owner.so_nfs4_owner.so_last_entry = entry; /* Deep copy OPEN args? */ if(args->argop == NFS4_OP_OPEN) { } /* Store new seqid */ owner->so_owner.so_nfs4_owner.so_seqid = seqid; }
void Copy_nfs4_state_req(state_owner_t * powner, seqid4 seqid, nfs_argop4 * args, compound_data_t * data, nfs_resop4 * resp, const char * tag) { /* Simplify use of this function when we may not be keeping any data for the * state owner */ if(powner == NULL) return; LogFullDebug(COMPONENT_STATE, "%s: saving response %p so_seqid %u new seqid %u", tag, powner, powner->so_owner.so_nfs4_owner.so_seqid, seqid); /* Free previous response */ nfs4_Compound_FreeOne(&powner->so_owner.so_nfs4_owner.so_resp); /* Copy new response */ nfs4_Compound_CopyResOne(&powner->so_owner.so_nfs4_owner.so_resp, resp); /* Deep copy OPEN args? */ if(powner->so_owner.so_nfs4_owner.so_args.argop == NFS4_OP_OPEN) { } /* Copy bnew args */ memcpy(&powner->so_owner.so_nfs4_owner.so_args, args, sizeof(powner->so_owner.so_nfs4_owner.so_args)); /* Copy new file */ powner->so_owner.so_nfs4_owner.so_last_pentry = data->current_entry; /* Deep copy OPEN args? */ if(args->argop == NFS4_OP_OPEN) { } /* Store new seqid */ powner->so_owner.so_nfs4_owner.so_seqid = seqid; }
/** * * Check_nfs4_seqid: Check NFS4 request for valid seqid for replay, next request, or BAD_SEQID. * * Returns TRUE if the request is the next seqid. * If the request is a replay, copies the saved response and returns FALSE. * Otherwise, sets status to NFS4ERR_BAD_SEQID and returns FALSE. * * In either case, on a FALSE return, the caller should send the resulting response back to the client. * */ bool_t Check_nfs4_seqid(state_owner_t * powner, seqid4 seqid, nfs_argop4 * args, compound_data_t * data, nfs_resop4 * resp, const char * tag) { seqid4 next; /* Check if any owner to verify seqid against */ if(powner == NULL) { LogFullDebug(COMPONENT_STATE, "%s: Unknown owner doesn't have saved seqid, req seqid %u", tag, seqid); return TRUE; } /* If this is a new state owner, client may start with any seqid */ if(powner->so_owner.so_nfs4_owner.so_last_pentry == NULL) { LogFullDebug(COMPONENT_STATE, "%s: New owner %p doesn't have saved seqid, req seqid %u", tag, powner, seqid); return TRUE; } /* Check for valid next seqid */ next = powner->so_owner.so_nfs4_owner.so_seqid + 1; LogFullDebug(COMPONENT_STATE, "%s: Check powner %p so_seqid %u next %u req seqid %u", tag, powner, powner->so_owner.so_nfs4_owner.so_seqid, next, seqid); if(seqid == next) return TRUE; /* All NFS4 responses have the status in the same place, so use any to set NFS4ERR_BAD_SEQID */ resp->nfs_resop4_u.oplock.status = NFS4ERR_BAD_SEQID; /* Now check for valid replay */ if(powner->so_owner.so_nfs4_owner.so_seqid != seqid) { LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay), expected seqid %u, returning NFS4ERR_BAD_SEQID", tag, seqid, powner->so_owner.so_nfs4_owner.so_seqid); return FALSE; } if(args->argop != powner->so_owner.so_nfs4_owner.so_args.argop) { LogDebug(COMPONENT_STATE, "%s: Invalid seqid in request %u (not replay - not same op), returning NFS4ERR_BAD_SEQID", tag, seqid); return FALSE; } if(powner->so_owner.so_nfs4_owner.so_last_pentry != data->current_entry) { LogDebug(COMPONENT_STATE, "%s: Invalid seqid in request %u (not replay - wrong file), returning NFS4ERR_BAD_SEQID", tag, seqid); return FALSE; } // TODO FSF: add more checks here... LogDebug(COMPONENT_STATE, "%s: Copying saved response for seqid %u", tag, seqid); /* Copy the saved response and tell caller to use it */ nfs4_Compound_CopyResOne(resp, &powner->so_owner.so_nfs4_owner.so_resp); return FALSE; }
/** * @brief Check NFS4 request for valid seqid for replay, next request, or BAD_SEQID. * * Returns true if the request is the next seqid. If the request is a * replay, copies the saved response and returns false. Otherwise, * sets status to NFS4ERR_BAD_SEQID and returns false. * * In either case, on a false return, the caller should send the * resulting response back to the client. * * @param[in] owner Owner to check * @param[in] seqid Seqid to check * @param[in] args Arguments of operation * @param[in] data Compound data * @param[out] resp Cached request, if replay * @param[in] tag Arbitrary string for logging/debugging * * @retval true if the caller should process the operation. * @retval false if the caller should immediately return the provides response. */ bool Check_nfs4_seqid(state_owner_t *owner, seqid4 seqid, nfs_argop4 *args, cache_entry_t *entry, nfs_resop4 *resp, const char *tag) { seqid4 next; char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; bool str_valid = false; /* Check if any owner to verify seqid against */ if (owner == NULL) { LogFullDebug(COMPONENT_STATE, "%s: Unknown owner doesn't have saved seqid, req seqid %u", tag, seqid); return true; } if (isDebug(COMPONENT_STATE)) { display_owner(&dspbuf, owner); str_valid = true; } /* If this is a new state owner, client may start with any seqid */ if (owner->so_owner.so_nfs4_owner.so_last_entry == NULL) { if (str_valid) LogFullDebug(COMPONENT_STATE, "%s: New {%s} doesn't have saved seqid, req seqid %u", tag, str, seqid); return true; } /* Check for valid next seqid */ next = owner->so_owner.so_nfs4_owner.so_seqid + 1; if (str_valid) LogFullDebug(COMPONENT_STATE, "%s: Check {%s} next %u req seqid %u", tag, str, next, seqid); if (seqid == next) return true; /* All NFS4 responses have the status in the same place, so use any to * set NFS4ERR_BAD_SEQID */ resp->nfs_resop4_u.oplock.status = NFS4ERR_BAD_SEQID; /* Now check for valid replay */ if (owner->so_owner.so_nfs4_owner.so_seqid != seqid) { if (str_valid) LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay), expected seqid for {%s}, returning NFS4ERR_BAD_SEQID", tag, seqid, str); return false; } if (args->argop != owner->so_owner.so_nfs4_owner.so_args.argop) { if (str_valid) LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay - not same op), expected seqid for {%s}, returning NFS4ERR_BAD_SEQID", tag, seqid, str); return false; } if (owner->so_owner.so_nfs4_owner.so_last_entry != entry) { if (str_valid) LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay - wrong file), expected seqid for {%s}, returning NFS4ERR_BAD_SEQID", tag, seqid, str); return false; } /** @todo FSF: add more checks here... */ if (str_valid) LogDebug(COMPONENT_STATE, "%s: Copying saved response for seqid %u into {%s}", tag, seqid, str); /* Copy the saved response and tell caller to use it */ nfs4_Compound_CopyResOne(resp, &owner->so_owner.so_nfs4_owner.so_resp); return false; }