int nfs4_op_destroy_session(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { DESTROY_SESSION4args * const arg_DESTROY_SESSION4 = &op->nfs_argop4_u.opdestroy_session; DESTROY_SESSION4res * const res_DESTROY_SESSION4 = &resp->nfs_resop4_u.opdestroy_session; sockaddr_t nw_addr; sockaddr_t client_addr; nfs41_session_t *session; resp->resop = NFS4_OP_DESTROY_SESSION; res_DESTROY_SESSION4->dsr_status = NFS4_OK; if (data->minorversion == 0) { res_DESTROY_SESSION4->dsr_status = NFS4ERR_INVAL; return res_DESTROY_SESSION4->dsr_status = NFS4ERR_INVAL; } if (!nfs41_Session_Get_Pointer(arg_DESTROY_SESSION4->dsa_sessionid, &session)) { res_DESTROY_SESSION4->dsr_status = NFS4ERR_BADSESSION; return res_DESTROY_SESSION4->dsr_status; } /* DESTROY_SESSION MUST be invoked on a connection that is associated * with the session being destroyed */ /* Copy the address coming over the wire. */ copy_xprt_addr(&nw_addr, data->req->rq_xprt); /* Copy the address recorded in the session. */ copy_xprt_addr(&client_addr, session->xprt); /* Compare these fields. */ if (!cmp_sockaddr(&nw_addr, &client_addr, false)) { res_DESTROY_SESSION4->dsr_status = NFS4ERR_CONN_NOT_BOUND_TO_SESSION; return res_DESTROY_SESSION4->dsr_status; } if (!nfs41_Session_Del(arg_DESTROY_SESSION4->dsa_sessionid)) res_DESTROY_SESSION4->dsr_status = NFS4ERR_BADSESSION; else res_DESTROY_SESSION4->dsr_status = NFS4_OK; /* Release ref taken in get_pointer */ dec_session_ref(session); return res_DESTROY_SESSION4->dsr_status; } /* nfs41_op_destroy_session */
/** * * nfs41_op_sequence: the NFS4_OP_SEQUENCE operation * * This functions handles the NFS4_OP_SEQUENCE operation in NFSv4. This function can be called only from nfs4_Compound. * * @param op [IN] pointer to nfs4_op arguments * @param data [INOUT] Pointer to the compound request's data * @param resp [IN] Pointer to nfs4_op results * * @return NFS4_OK if successfull, other values show an error. * * @see all the nfs4_op_<*> function * @see nfs4_Compound * */ int nfs41_op_sequence(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { #define arg_SEQUENCE4 op->nfs_argop4_u.opsequence #define res_SEQUENCE4 resp->nfs_resop4_u.opsequence nfs41_session_t *psession; resp->resop = NFS4_OP_SEQUENCE; res_SEQUENCE4.sr_status = NFS4_OK; /* OP_SEQUENCE is always the first operation of the request */ if(data->oppos != 0) { res_SEQUENCE4.sr_status = NFS4ERR_SEQUENCE_POS; return res_SEQUENCE4.sr_status; } if(!nfs41_Session_Get_Pointer(arg_SEQUENCE4.sa_sessionid, &psession)) { res_SEQUENCE4.sr_status = NFS4ERR_BADSESSION; return res_SEQUENCE4.sr_status; } /* Check is slot is compliant with ca_maxrequests */ if(arg_SEQUENCE4.sa_slotid >= psession->fore_channel_attrs.ca_maxrequests) { res_SEQUENCE4.sr_status = NFS4ERR_BADSLOT; return res_SEQUENCE4.sr_status; } /* By default, no DRC replay */ data->use_drc = FALSE; P(psession->slots[arg_SEQUENCE4.sa_slotid].lock); if(psession->slots[arg_SEQUENCE4.sa_slotid].sequence + 1 != arg_SEQUENCE4.sa_sequenceid) { if(psession->slots[arg_SEQUENCE4.sa_slotid].sequence == arg_SEQUENCE4.sa_sequenceid) { if(psession->slots[arg_SEQUENCE4.sa_slotid].cache_used == TRUE) { /* Replay operation through the DRC */ data->use_drc = TRUE; data->pcached_res = psession->slots[arg_SEQUENCE4.sa_slotid].cached_result; res_SEQUENCE4.sr_status = NFS4_OK; return res_SEQUENCE4.sr_status; } else { /* Illegal replay */ res_SEQUENCE4.sr_status = NFS4ERR_RETRY_UNCACHED_REP; return res_SEQUENCE4.sr_status; } } V(psession->slots[arg_SEQUENCE4.sa_slotid].lock); res_SEQUENCE4.sr_status = NFS4ERR_SEQ_MISORDERED; return res_SEQUENCE4.sr_status; } /* Keep memory of the session in the COMPOUND's data */ data->psession = psession; /* Update the sequence id within the slot */ psession->slots[arg_SEQUENCE4.sa_slotid].sequence += 1; memcpy((char *)res_SEQUENCE4.SEQUENCE4res_u.sr_resok4.sr_sessionid, (char *)arg_SEQUENCE4.sa_sessionid, NFS4_SESSIONID_SIZE); res_SEQUENCE4.SEQUENCE4res_u.sr_resok4.sr_sequenceid = psession->slots[arg_SEQUENCE4.sa_slotid].sequence; res_SEQUENCE4.SEQUENCE4res_u.sr_resok4.sr_slotid = arg_SEQUENCE4.sa_slotid; res_SEQUENCE4.SEQUENCE4res_u.sr_resok4.sr_highest_slotid = NFS41_NB_SLOTS - 1; res_SEQUENCE4.SEQUENCE4res_u.sr_resok4.sr_target_highest_slotid = arg_SEQUENCE4.sa_slotid; /* Maybe not the best choice */ res_SEQUENCE4.SEQUENCE4res_u.sr_resok4.sr_status_flags = 0; /* What is to be set here ? */ if(arg_SEQUENCE4.sa_cachethis == TRUE) { data->pcached_res = psession->slots[arg_SEQUENCE4.sa_slotid].cached_result; psession->slots[arg_SEQUENCE4.sa_slotid].cache_used = TRUE; } else { data->pcached_res = NULL; psession->slots[arg_SEQUENCE4.sa_slotid].cache_used = FALSE; } V(psession->slots[arg_SEQUENCE4.sa_slotid].lock); res_SEQUENCE4.sr_status = NFS4_OK; return res_SEQUENCE4.sr_status; } /* nfs41_op_sequence */
/** * @brief the NFS4_OP_SEQUENCE operation * * @param[in] op nfs4_op arguments * @param[in,out] data Compound request's data * @param[out] resp nfs4_op results * * @return per RFC5661, p. 374 * * @see nfs4_Compound * */ int nfs4_op_sequence(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SEQUENCE4args * const arg_SEQUENCE4 = &op->nfs_argop4_u.opsequence; SEQUENCE4res * const res_SEQUENCE4 = &resp->nfs_resop4_u.opsequence; nfs41_session_t *session; resp->resop = NFS4_OP_SEQUENCE; res_SEQUENCE4->sr_status = NFS4_OK; if (data->minorversion == 0) { res_SEQUENCE4->sr_status = NFS4ERR_INVAL; return res_SEQUENCE4->sr_status; } /* OP_SEQUENCE is always the first operation of the request */ if (data->oppos != 0) { res_SEQUENCE4->sr_status = NFS4ERR_SEQUENCE_POS; return res_SEQUENCE4->sr_status; } if (!nfs41_Session_Get_Pointer(arg_SEQUENCE4->sa_sessionid, &session)) { if (nfs_in_grace()) { memcpy(res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_sessionid, arg_SEQUENCE4->sa_sessionid, NFS4_SESSIONID_SIZE); res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sequenceid = arg_SEQUENCE4->sa_sequenceid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_slotid = arg_SEQUENCE4->sa_slotid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_highest_slotid = NFS41_NB_SLOTS - 1; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_target_highest_slotid = arg_SEQUENCE4->sa_slotid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_status_flags = SEQ4_STATUS_RESTART_RECLAIM_NEEDED; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s flags 0x%X", nfsstat4_to_str(res_SEQUENCE4->sr_status), res_SEQUENCE4->SEQUENCE4res_u.sr_resok4. sr_status_flags); } else { res_SEQUENCE4->sr_status = NFS4ERR_BADSESSION; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); } return res_SEQUENCE4->sr_status; } /* session->refcount +1 */ LogDebug(COMPONENT_SESSIONS, "SEQUENCE session=%p", session); /* Check if lease is expired and reserve it */ pthread_mutex_lock(&session->clientid_record->cid_mutex); if (!reserve_lease(session->clientid_record)) { pthread_mutex_unlock(&session->clientid_record->cid_mutex); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_EXPIRED; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); return res_SEQUENCE4->sr_status; } data->preserved_clientid = session->clientid_record; pthread_mutex_unlock(&session->clientid_record->cid_mutex); /* Check is slot is compliant with ca_maxrequests */ if (arg_SEQUENCE4->sa_slotid >= session->fore_channel_attrs.ca_maxrequests) { dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_BADSLOT; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); return res_SEQUENCE4->sr_status; } /* By default, no DRC replay */ data->use_drc = false; pthread_mutex_lock(&session->slots[arg_SEQUENCE4->sa_slotid].lock); if (session->slots[arg_SEQUENCE4->sa_slotid].sequence + 1 != arg_SEQUENCE4->sa_sequenceid) { if (session->slots[arg_SEQUENCE4->sa_slotid].sequence == arg_SEQUENCE4->sa_sequenceid) { #if IMPLEMENT_CACHETHIS /** @todo * * Ganesha always caches result anyway so ignore * cachethis */ if (session->slots[arg_SEQUENCE4->sa_slotid] .cache_used) { #endif /* Replay operation through the DRC */ data->use_drc = true; data->cached_res = &session->slots[arg_SEQUENCE4->sa_slotid]. cached_result; LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "Use sesson slot %" PRIu32 "=%p for DRC", arg_SEQUENCE4->sa_slotid, data->cached_res); pthread_mutex_unlock(&session-> slots[arg_SEQUENCE4->sa_slotid].lock); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4_OK; return res_SEQUENCE4->sr_status; #if IMPLEMENT_CACHETHIS } else { /* Illegal replay */ pthread_mutex_unlock(&session-> slots[arg_SEQUENCE4->sa_slotid].lock); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_RETRY_UNCACHED_REP; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4-> sr_status)); return res_SEQUENCE4->sr_status; } #endif } pthread_mutex_unlock(&session-> slots[arg_SEQUENCE4->sa_slotid].lock); dec_session_ref(session); res_SEQUENCE4->sr_status = NFS4ERR_SEQ_MISORDERED; LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "SEQUENCE returning status %s", nfsstat4_to_str(res_SEQUENCE4->sr_status)); return res_SEQUENCE4->sr_status; } /* Keep memory of the session in the COMPOUND's data */ data->session = session; /* Record the sequenceid and slotid in the COMPOUND's data */ data->sequence = arg_SEQUENCE4->sa_sequenceid; data->slot = arg_SEQUENCE4->sa_slotid; /* Update the sequence id within the slot */ session->slots[arg_SEQUENCE4->sa_slotid].sequence += 1; memcpy(res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sessionid, arg_SEQUENCE4->sa_sessionid, NFS4_SESSIONID_SIZE); res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sequenceid = session->slots[arg_SEQUENCE4->sa_slotid].sequence; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_slotid = arg_SEQUENCE4->sa_slotid; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_highest_slotid = NFS41_NB_SLOTS - 1; res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_target_highest_slotid = arg_SEQUENCE4->sa_slotid; /* Maybe not the best choice */ res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_status_flags = 0; if (nfs_rpc_get_chan(session->clientid_record, 0) == NULL) { res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_status_flags |= SEQ4_STATUS_CB_PATH_DOWN; } #if IMPLEMENT_CACHETHIS /* Ganesha always caches result anyway so ignore cachethis */ if (arg_SEQUENCE4->sa_cachethis) { #endif data->cached_res = &session->slots[arg_SEQUENCE4->sa_slotid].cached_result; session->slots[arg_SEQUENCE4->sa_slotid].cache_used = true; LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "Use sesson slot %" PRIu32 "=%p for DRC", arg_SEQUENCE4->sa_slotid, data->cached_res); #if IMPLEMENT_CACHETHIS } else { data->cached_res = NULL; session->slots[arg_SEQUENCE4->sa_slotid].cache_used = false; LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID, "Don't use sesson slot %" PRIu32 "=NULL for DRC", arg_SEQUENCE4->sa_slotid); } #endif pthread_mutex_unlock(&session->slots[arg_SEQUENCE4->sa_slotid].lock); /* If we were successful, stash the clientid in the request * context. */ data->req_ctx->clientid = &data->session->clientid; res_SEQUENCE4->sr_status = NFS4_OK; return res_SEQUENCE4->sr_status; } /* nfs41_op_sequence */