/** * * nfs41_Session_Del * * This routine removes a session from the sessions's hashtable. * * @param sessionid [IN] sessionid, used as a hash key * * @return 1 if ok, 0 otherwise. * */ int nfs41_Session_Del(char sessionid[NFS4_SESSIONID_SIZE]) { hash_buffer_t buffkey, old_key, old_value; if(isFullDebug(COMPONENT_SESSIONS)) { char str[NFS4_SESSIONID_SIZE *2 + 1]; sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE); LogFullDebug(COMPONENT_SESSIONS, " ----- DelSession : %s\n", str); } buffkey.pdata = (caddr_t) sessionid; buffkey.len = NFS4_SESSIONID_SIZE; if(HashTable_Del(ht_session_id, &buffkey, &old_key, &old_value) == HASHTABLE_SUCCESS) { /* free the key that was stored in hash table */ Mem_Free((void *)old_key.pdata); /* State is managed in stuff alloc, no fre is needed for old_value.pdata */ return 1; } else return 0; } /* nfs41_Session_Del */
/** * * nfs41_Session_Update * * This routine updates a session from the sessions's hashtable. * * @param psession [IN] pointer to the sessionid to be checked. * @param psession_data [IN] new session * * @return 1 if ok, 0 otherwise. * */ int nfs41_Session_Update(char sessionid[NFS4_SESSIONID_SIZE], nfs41_session_t * psession_data) { hash_buffer_t buffkey; hash_buffer_t buffval; if(isFullDebug(COMPONENT_SESSIONS)) { char str[NFS4_SESSIONID_SIZE *2 + 1]; sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE); LogFullDebug(COMPONENT_SESSIONS, " ----- UpdateSession : %s\n", str); } buffkey.pdata = (caddr_t) sessionid; buffkey.len = NFS4_SESSIONID_SIZE; if(HashTable_Get(ht_session_id, &buffkey, &buffval) != HASHTABLE_SUCCESS) { LogFullDebug(COMPONENT_SESSIONS, "---> nfs41_Session_Update NOT FOUND !!!!!!\n"); return 0; } memcpy(buffval.pdata, psession_data, sizeof(nfs41_session_t)); LogFullDebug(COMPONENT_SESSIONS, "---> nfs41_Session_Update Found :-)\n"); return 1; } /* nfs41_Session_Update */
fsal_status_t fsal_internal_fd2handle( fsal_op_context_t *p_context, int fd, fsal_handle_t *p_handle) { int rc = 0; int errsv; int mnt_id = 0; memset(p_handle, 0, sizeof(vfsfsal_handle_t)); ((vfsfsal_handle_t *)p_handle)->data.vfs_handle.handle_bytes = VFS_HANDLE_LEN ; if( ( rc = vfs_fd_to_handle( fd, &((vfsfsal_handle_t *)p_handle)->data.vfs_handle, &mnt_id ) ) ) { errsv = errno; ReturnCode(posix2fsal_error(errsv), errsv); } #if 0 { char str[1024] ; sprint_mem( str, p_handle->data.vfs_handle.handle, p_handle->data.vfs_handle.handle_bytes ) ; printf( "=====> fsal_internal_fd2handle: type=%u bytes=%u|%s\n", p_handle->data.vfs_handle.handle_type, p_handle->data.vfs_handle.handle_bytes, str ) ; } #endif ReturnCode(ERR_FSAL_NO_ERROR, 0); } /* fsal_internal_fd2handle */
unsigned long session_id_rbt_hash_func(hash_parameter_t * p_hparam, hash_buffer_t * buffclef) { u_int32_t i1 = 0; u_int32_t i2 = 0; u_int32_t i3 = 0; u_int32_t i4 = 0; if(isFullDebug(COMPONENT_SESSIONS)) { char str[NFS4_SESSIONID_SIZE *2 + 1]; sprint_mem(str, (char *)buffclef->pdata, NFS4_SESSIONID_SIZE); LogFullDebug(COMPONENT_SESSIONS, " ----- session_id_rbt_hash_func : %s\n", str); } memcpy(&i1, &(buffclef->pdata[0]), sizeof(u_int32_t)); memcpy(&i2, &(buffclef->pdata[4]), sizeof(u_int32_t)); memcpy(&i3, &(buffclef->pdata[8]), sizeof(u_int32_t)); memcpy(&i4, &(buffclef->pdata[12]), sizeof(u_int32_t)); LogFullDebug(COMPONENT_SESSIONS, "---> session_id_rbt_hash_func=%lu\n", (unsigned long)(i1 ^ i2 ^ i3)); return (unsigned long)(i1 ^ i2 ^ i3 | i4); } /* session_id_rbt_hash_func */
/** * @brief Update stateid and set current * * We increment the seqid, handling wraparound, and copy the id into * the response. * * @param[in,out] state State to update * @param[out] resp Stateid in response * @param[in,out] data Compound data to upddate with current stateid * (may be NULL) * @param[in] tag Arbitrary text for debug/log */ void update_stateid(state_t *state, stateid4 *resp, compound_data_t *data, const char *tag) { /* Increment state_seqid, handling wraparound */ state->state_seqid += 1; if (state->state_seqid == 0) state->state_seqid = 1; /* Copy stateid into current for later use */ if (data) { COPY_STATEID(&data->current_stateid, state); data->current_stateid_valid = true; } /* Copy stateid into response */ COPY_STATEID(resp, state); if (isFullDebug(COMPONENT_STATE)) { char str[OTHERSIZE * 2 + 1 + 6]; sprint_mem(str, (char *)state->stateid_other, OTHERSIZE); sprintf(str + OTHERSIZE * 2, ":%u", (unsigned int)state->state_seqid); LogDebug(COMPONENT_STATE, "Update %s stateid to %s for response", tag, str); } }
fsal_status_t fsal_internal_handle2fd(fsal_op_context_t * p_context, fsal_handle_t * p_handle, int *pfd, int oflags) { int rc = 0; int errsv; if(!p_handle || !pfd || !p_context) ReturnCode(ERR_FSAL_FAULT, 0); #if 0 { char str[1024] ; sprint_mem( str, phandle->data.vfs_handle.handle, phandle->data.vfs_handle.handle_bytes ) ; printf( "=====> fsal_internal_handle2fd: type=%u bytes=%u|%s\n", phandle->data.vfs_handle.handle_type, phandle->data.vfs_handle.handle_bytes, str ) ; } #endif rc = vfs_open_by_handle( ((vfsfsal_op_context_t *)p_context)->export_context->mount_root_fd, &((vfsfsal_handle_t *)p_handle)->data.vfs_handle, oflags ) ; if(rc == -1) { errsv = errno; ReturnCode(posix2fsal_error(errsv), errsv); } *pfd = rc; ReturnCode(ERR_FSAL_NO_ERROR, 0); } /* fsal_internal_handle2fd */
/** * * nfs41_Session_Set * * This routine sets a session into the sessions's hashtable. * * @param psession [IN] pointer to the sessionid to be checked. * * @return 1 if ok, 0 otherwise. * */ int nfs41_Session_Set(char sessionid[NFS4_SESSIONID_SIZE], nfs41_session_t * psession_data) { hash_buffer_t buffkey; hash_buffer_t buffval; if(isFullDebug(COMPONENT_SESSIONS)) { char str[NFS4_SESSIONID_SIZE *2 + 1]; sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE); LogFullDebug(COMPONENT_SESSIONS, " ----- SetSSession : %s\n", str); } if((buffkey.pdata = (caddr_t) Mem_Alloc(NFS4_SESSIONID_SIZE)) == NULL) return 0; memcpy(buffkey.pdata, sessionid, NFS4_SESSIONID_SIZE); buffkey.len = NFS4_SESSIONID_SIZE; buffval.pdata = (caddr_t) psession_data; buffval.len = sizeof(nfs41_session_t); if(HashTable_Test_And_Set (ht_session_id, &buffkey, &buffval, HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS) return 0; return 1; } /* nfs41_Session_Set */
void sprint_fhandle2(char *str, fhandle2 *fh) { char *tmp = str + sprintf(str, "File Handle V2: "); sprint_mem(tmp, (char *) fh, 32); } /* sprint_fhandle2 */
int nfs4_op_setclientid_confirm(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETCLIENTID_CONFIRM4args * const arg_SETCLIENTID_CONFIRM4 = &op->nfs_argop4_u.opsetclientid_confirm; SETCLIENTID_CONFIRM4res * const res_SETCLIENTID_CONFIRM4 = &resp->nfs_resop4_u.opsetclientid_confirm; nfs_client_id_t *conf = NULL; nfs_client_id_t *unconf = NULL; nfs_client_record_t *client_record; clientid4 clientid = 0; char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; const char *str_client_addr = "(unknown)"; /* The client name, for gratuitous logging */ char str_client[CLIENTNAME_BUFSIZE]; /* Display buffer for client name */ struct display_buffer dspbuf_client = { sizeof(str_client), str_client, str_client}; /* The clientid4 broken down into fields */ char str_clientid4[DISPLAY_CLIENTID_SIZE]; /* Display buffer for clientid4 */ struct display_buffer dspbuf_clientid4 = { sizeof(str_clientid4), str_clientid4, str_clientid4}; int rc; /* Make sure str_client is always printable even * if log level changes midstream. */ display_printf(&dspbuf_client, "(unknown)"); display_reset_buffer(&dspbuf_client); resp->resop = NFS4_OP_SETCLIENTID_CONFIRM; res_SETCLIENTID_CONFIRM4->status = NFS4_OK; clientid = arg_SETCLIENTID_CONFIRM4->clientid; display_clientid(&dspbuf_clientid4, clientid); if (data->minorversion > 0) { res_SETCLIENTID_CONFIRM4->status = NFS4ERR_NOTSUPP; return res_SETCLIENTID_CONFIRM4->status; } if (op_ctx->client != NULL) str_client_addr = op_ctx->client->hostaddr_str; if (isDebug(COMPONENT_CLIENTID)) { sprint_mem(str_verifier, arg_SETCLIENTID_CONFIRM4->setclientid_confirm, NFS4_VERIFIER_SIZE); } else { str_verifier[0] = '\0'; } LogDebug(COMPONENT_CLIENTID, "SETCLIENTID_CONFIRM client addr=%s clientid=%s setclientid_confirm=%s", str_client_addr, str_clientid4, str_verifier); /* First try to look up unconfirmed record */ rc = nfs_client_id_get_unconfirmed(clientid, &unconf); if (rc == CLIENT_ID_SUCCESS) { client_record = unconf->cid_client_record; if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogFullDebug(COMPONENT_CLIENTID, "Found %s", str); } } else { rc = nfs_client_id_get_confirmed(clientid, &conf); if (rc != CLIENT_ID_SUCCESS) { /* No record whatsoever of this clientid */ LogDebug(COMPONENT_CLIENTID, "%s clientid = %s", clientid_error_to_str(rc), str_clientid4); res_SETCLIENTID_CONFIRM4->status = clientid_error_to_nfsstat_no_expire(rc); return res_SETCLIENTID_CONFIRM4->status; } client_record = conf->cid_client_record; if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogFullDebug(COMPONENT_CLIENTID, "Found %s", str); } } PTHREAD_MUTEX_lock(&client_record->cr_mutex); inc_client_record_ref(client_record); if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_record(&dspbuf, client_record); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } /* At this point one and only one of pconf and punconf is non-NULL */ if (unconf != NULL) { /* First must match principal */ if (!nfs_compare_clientcred(&unconf->cid_credential, &data->credential) || op_ctx->client == NULL || unconf->gsh_client == NULL || op_ctx->client != unconf->gsh_client) { if (isDebug(COMPONENT_CLIENTID)) { char *unconfirmed_addr = "(unknown)"; if (unconf->gsh_client != NULL) unconfirmed_addr = unconf->gsh_client->hostaddr_str; LogDebug(COMPONENT_CLIENTID, "Unconfirmed ClientId %s->'%s': Principals do not match... unconfirmed addr=%s Return NFS4ERR_CLID_INUSE", str_clientid4, str_client_addr, unconfirmed_addr); } res_SETCLIENTID_CONFIRM4->status = NFS4ERR_CLID_INUSE; dec_client_id_ref(unconf); goto out; } else if (unconf->cid_confirmed == CONFIRMED_CLIENT_ID && memcmp(unconf->cid_verifier, arg_SETCLIENTID_CONFIRM4->setclientid_confirm, NFS4_VERIFIER_SIZE) == 0) { /* We must have raced with another SETCLIENTID_CONFIRM */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = { sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "Race against confirm for %s", str); } res_SETCLIENTID_CONFIRM4->status = NFS4_OK; dec_client_id_ref(unconf); goto out; } else if (unconf->cid_confirmed != UNCONFIRMED_CLIENT_ID) { /* We raced with another thread that dealt * with this unconfirmed record. Release our * reference, and pretend we didn't find a * record. */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = { sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "Race against expire for %s", str); } res_SETCLIENTID_CONFIRM4->status = NFS4ERR_STALE_CLIENTID; dec_client_id_ref(unconf); goto out; } } if (conf != NULL) { if (isDebug(COMPONENT_CLIENTID) && conf != NULL) display_clientid_name(&dspbuf_client, conf); /* First must match principal */ if (!nfs_compare_clientcred(&conf->cid_credential, &data->credential) || op_ctx->client == NULL || conf->gsh_client == NULL || op_ctx->client != conf->gsh_client) { if (isDebug(COMPONENT_CLIENTID)) { char *confirmed_addr = "(unknown)"; if (conf->gsh_client != NULL) confirmed_addr = conf->gsh_client->hostaddr_str; LogDebug(COMPONENT_CLIENTID, "Confirmed ClientId %s->%s addr=%s: Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", str_clientid4, str_client, str_client_addr, confirmed_addr); } res_SETCLIENTID_CONFIRM4->status = NFS4ERR_CLID_INUSE; } else if (memcmp( conf->cid_verifier, arg_SETCLIENTID_CONFIRM4->setclientid_confirm, NFS4_VERIFIER_SIZE) == 0) { /* In this case, the record was confirmed and * we have received a retry */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = { sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogDebug(COMPONENT_CLIENTID, "Retry confirm for %s", str); } res_SETCLIENTID_CONFIRM4->status = NFS4_OK; } else { /* This is a case not covered... Return * NFS4ERR_CLID_INUSE */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = { sizeof(str), str, str}; char str_conf_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; sprint_mem(str_conf_verifier, conf->cid_verifier, NFS4_VERIFIER_SIZE); display_client_id_rec(&dspbuf, conf); LogDebug(COMPONENT_CLIENTID, "Confirm verifier=%s doesn't match verifier=%s for %s", str_conf_verifier, str_verifier, str); } res_SETCLIENTID_CONFIRM4->status = NFS4ERR_CLID_INUSE; } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); goto out; } /* We don't need to do any further principal checks, we can't * have a confirmed clientid record with a different principal * than the unconfirmed record. Also, at this point, we have * a matching unconfirmed clientid (punconf != NULL and pconf * == NULL). */ /* Make sure we have a reference to the confirmed clientid * record if any */ if (conf == NULL) { conf = client_record->cr_confirmed_rec; if (isDebug(COMPONENT_CLIENTID) && conf != NULL) display_clientid_name(&dspbuf_client, conf); /* Need a reference to the confirmed record for below */ if (conf != NULL) inc_client_id_ref(conf); } if (conf != NULL && conf->cid_clientid != clientid) { /* Old confirmed record - need to expire it */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogDebug(COMPONENT_CLIENTID, "Expiring %s", str); } /* Expire clientid and release our reference. */ nfs_client_id_expire(conf, false); dec_client_id_ref(conf); conf = NULL; } if (conf != NULL) { /* At this point we are updating the confirmed * clientid. Update the confirmed record from the * unconfirmed record. */ if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogFullDebug(COMPONENT_CLIENTID, "Updating from %s", str); } /* Copy callback information into confirmed clientid record */ memcpy(conf->cid_cb.v40.cb_client_r_addr, unconf->cid_cb.v40.cb_client_r_addr, sizeof(conf->cid_cb.v40.cb_client_r_addr)); conf->cid_cb.v40.cb_addr = unconf->cid_cb.v40.cb_addr; conf->cid_cb.v40.cb_program = unconf->cid_cb.v40.cb_program; conf->cid_cb.v40.cb_callback_ident = unconf->cid_cb.v40.cb_callback_ident; nfs_rpc_destroy_chan(&conf->cid_cb.v40.cb_chan); memcpy(conf->cid_verifier, unconf->cid_verifier, NFS4_VERIFIER_SIZE); /* unhash the unconfirmed clientid record */ remove_unconfirmed_client_id(unconf); /* Release our reference to the unconfirmed entry */ dec_client_id_ref(unconf); if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogDebug(COMPONENT_CLIENTID, "Updated %s", str); } /* Check and update call back channel state */ if (nfs_param.nfsv4_param.allow_delegations && nfs_test_cb_chan(conf) != RPC_SUCCESS) { set_cb_chan_down(conf, true); LogCrit(COMPONENT_CLIENTID, "setclid confirm: Callback channel is down"); } else { set_cb_chan_down(conf, false); LogDebug(COMPONENT_CLIENTID, "setclid confirm: Callback channel is UP"); } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); } else { /* This is a new clientid */ if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogFullDebug(COMPONENT_CLIENTID, "Confirming new %s", str); } rc = nfs_client_id_confirm(unconf, COMPONENT_CLIENTID); if (rc != CLIENT_ID_SUCCESS) { res_SETCLIENTID_CONFIRM4->status = clientid_error_to_nfsstat_no_expire(rc); LogEvent(COMPONENT_CLIENTID, "FAILED to confirm client"); /* Release our reference to the unconfirmed record */ dec_client_id_ref(unconf); goto out; } /* check if the client can perform reclaims */ nfs4_chk_clid(unconf); if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "Confirmed %s", str); } /* Check and update call back channel state */ if (nfs_param.nfsv4_param.allow_delegations && nfs_test_cb_chan(unconf) != RPC_SUCCESS) { set_cb_chan_down(unconf, true); LogCrit(COMPONENT_CLIENTID, "setclid confirm: Callback channel is down"); } else { set_cb_chan_down(unconf, false); LogDebug(COMPONENT_CLIENTID, "setclid confirm: Callback channel is UP"); } /* Release our reference to the now confirmed record */ dec_client_id_ref(unconf); } if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_record(&dspbuf, client_record); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } /* Successful exit */ res_SETCLIENTID_CONFIRM4->status = NFS4_OK; out: PTHREAD_MUTEX_unlock(&client_record->cr_mutex); /* Release our reference to the client record and return */ dec_client_record_ref(client_record); return res_SETCLIENTID_CONFIRM4->status; }
void nfs4_sprint_fhandle(nfs_fh4 * fh4p, char *outstr) { char *tmp = outstr + sprintf(outstr, "File Handle V4: Len=%u ", fh4p->nfs_fh4_len); sprint_mem(tmp, (char *)fh4p->nfs_fh4_val, fh4p->nfs_fh4_len); } /* nfs4_sprint_fhandle */
void sprint_buff(char *str, char *buff, int len) { char *tmp = str + sprintf(str, " Len=%u Buff=%p Val: ", len, buff); sprint_mem(tmp, buff, len); } /* sprint_buff */
void sprint_fhandle_nlm(char *str, netobj *fh) { char *tmp = str + sprintf(str, "File Handle V3: Len=%u ", fh->n_len); sprint_mem(tmp, fh->n_bytes, fh->n_len); } /* sprint_fhandle_nlm */
void sprint_fhandle4(char *str, nfs_fh4 *fh) { char *tmp = str + sprintf(str, "File Handle V4: Len=%u ", fh->nfs_fh4_len); sprint_mem(tmp, fh->nfs_fh4_val, fh->nfs_fh4_len); } /* sprint_fhandle4 */
int nfs41_op_exchange_id(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; nfs_client_record_t * pclient_record; nfs_client_id_t * pconf; nfs_client_id_t * punconf; int rc; int len; char * temp; bool_t update; const char * update_str; log_components_t component = COMPONENT_CLIENTID; #if 0 /** @todo: plante le client sous windows. Ai-je réellement besoin de cela ???? */ /* Check flags value (test EID4) */ if(arg_EXCHANGE_ID4.eia_flags & all_eia_flags != arg_EXCHANGE_ID4.eia_flags) { res_EXCHANGE_ID4.eir_status = NFS4ERR_INVAL; return res_EXCHANGE_ID4.eir_status; } #endif if(isDebug(COMPONENT_SESSIONS)) component = COMPONENT_SESSIONS; #define arg_EXCHANGE_ID4 op->nfs_argop4_u.opexchange_id #define res_EXCHANGE_ID4 resp->nfs_resop4_u.opexchange_id #define res_EXCHANGE_ID4_ok resp->nfs_resop4_u.opexchange_id.EXCHANGE_ID4res_u.eir_resok4 resp->resop = NFS4_OP_EXCHANGE_ID; update = (arg_EXCHANGE_ID4.eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) != 0; if(isDebug(component)) { DisplayOpaqueValue(arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val, arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len, str_client); sprint_mem(str_verifier, arg_EXCHANGE_ID4.eia_clientowner.co_verifier, NFS4_VERIFIER_SIZE); update_str = update ? "UPDATE" : "NO UPDATE"; } LogDebug(component, "EXCHANGE_ID Client addr=%s id=%s verf=%s %s --------------------", data->pworker->hostaddr_str, str_client, str_verifier, update_str); /* Do we already have one or more records for client id (x)? */ pclient_record = get_client_record(arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val, arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len); if(pclient_record == NULL) { /* Some major failure */ LogCrit(component, "EXCHANGE_ID failed"); res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT; return res_EXCHANGE_ID4.eir_status; } /* * The following checks are based on RFC5661 * * This attempts to implement the logic described in 18.35.4. IMPLEMENTATION */ P(pclient_record->cr_mutex); if(isFullDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_record(pclient_record, str); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p", str, pclient_record->cr_pconfirmed_id, pclient_record->cr_punconfirmed_id); } pconf = pclient_record->cr_pconfirmed_id; if(pconf != NULL) { /* Need a reference to the confirmed record for below */ inc_client_id_ref(pconf); } if(pconf != NULL && !update) { /* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A not set */ /** @todo FSF: old code ifdefed out nfs_compare_clientcred with _NFSV4_COMPARE_CRED_IN_EXCHANGE_ID */ if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) || !cmp_sockaddr(&pconf->cid_client_addr, &data->pworker->hostaddr, IGNORE_PORT)) { /** @todo FSF: should also check if there is no state */ P(pconf->cid_mutex); if(valid_lease(pconf)) { V(pconf->cid_mutex); /* CASE 3, client collisions, old clientid is expired */ if(isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_id_rec(pconf, str); LogDebug(COMPONENT_CLIENTID, "Expiring %s", str); } /* Expire clientid and release our reference. */ nfs_client_id_expire(pconf); dec_client_id_ref(pconf); pconf = NULL; } else { V(pconf->cid_mutex); /* CASE 3, client collisions, old clientid is not expired */ if(isDebug(component)) { char confirmed_addr[SOCK_NAME_MAX]; sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr)); LogDebug(component, "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", pconf->cid_clientid, str_client, confirmed_addr); } res_EXCHANGE_ID4.eir_status = NFS4ERR_CLID_INUSE; /* Release our reference to the confirmed clientid. */ dec_client_id_ref(pconf); goto out; } } else if(memcmp(arg_EXCHANGE_ID4.eia_clientowner.co_verifier, pconf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) { /* CASE 2, Non-Update on Existing Client ID */ /* Return what was last returned without changing any refcounts */ LogDebug(COMPONENT_CLIENTID, "Non-update of confirmed ClientId %"PRIx64"->%s", pconf->cid_clientid, str_client); punconf = pconf; goto return_ok; } else { /* CASE 5, client restart */ /** @todo FSF: expire old clientid? */ LogDebug(component, "Restarted ClientId %"PRIx64"->%s", pconf->cid_clientid, str_client); } } else if(pconf != NULL) { /* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A set */ if(memcmp(arg_EXCHANGE_ID4.eia_clientowner.co_verifier, pconf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) { /** @todo FSF: old code ifdefed out nfs_compare_clientcred with _NFSV4_COMPARE_CRED_IN_EXCHANGE_ID */ if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) || !cmp_sockaddr(&pconf->cid_client_addr, &data->pworker->hostaddr, IGNORE_PORT)) { /* CASE 9, Update but wrong principal */ if(isDebug(component)) { char confirmed_addr[SOCK_NAME_MAX]; sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr)); LogDebug(component, "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_PERM", pconf->cid_clientid, str_client, confirmed_addr); } res_EXCHANGE_ID4.eir_status = NFS4ERR_PERM; } else { /* CASE 6, Update */ /** @todo: this is not implemented, the things it updates aren't even tracked */ LogMajor(component, "EXCHANGE_ID Update not supported"); res_EXCHANGE_ID4.eir_status = NFS4ERR_NOTSUPP; } } else { /* CASE 8, Update but wrong verifier */ if(isDebug(component)) { char str_old_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; sprint_mem(str_old_verifier, pconf->cid_incoming_verifier, NFS4_VERIFIER_SIZE); LogDebug(component, "Confirmed clientid %"PRIx64"->'%s': Verifiers do not match... confirmed verifier=%s", pconf->cid_clientid, str_client, str_old_verifier); } res_EXCHANGE_ID4.eir_status = NFS4ERR_NOT_SAME; } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(pconf); goto out; } else if(pconf == NULL && update) { LogDebug(component, "No confirmed clientid to update for %s", str_client); res_EXCHANGE_ID4.eir_status = NFS4ERR_NOENT; goto out; } /* At this point, no matter what the case was above, we should remove any * pre-existing unconfirmed record. */ punconf = pclient_record->cr_punconfirmed_id; if(punconf != NULL) { /* CASE 4, replacement of unconfirmed record */ /* Delete the unconfirmed clientid record */ if(isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_id_rec(punconf, str); LogDebug(COMPONENT_CLIENTID, "Replacing %s", str); } /* unhash the clientid record */ remove_unconfirmed_client_id(punconf); } /* Now we can proceed to build the new unconfirmed record. We have determined * the clientid and setclientid_confirm values above. */ punconf = create_client_id(0, pclient_record, &data->pworker->hostaddr, &data->credential); if(punconf == NULL) { /* Error already logged, return */ res_EXCHANGE_ID4.eir_status = NFS4ERR_RESOURCE; goto out; } memcpy(punconf->cid_incoming_verifier, arg_EXCHANGE_ID4.eia_clientowner.co_verifier, NFS4_VERIFIER_SIZE); if(gethostname(punconf->cid_server_owner, sizeof(punconf->cid_server_owner)) == -1) { /* Free the clientid record and return */ free_client_id(punconf); res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT; goto out; } snprintf(punconf->cid_server_scope, sizeof(punconf->cid_server_scope), "%s_NFS-Ganesha", punconf->cid_server_owner); rc = nfs_client_id_insert(punconf); if(rc != CLIENT_ID_SUCCESS) { /* Record is already freed, return. */ res_EXCHANGE_ID4.eir_status = clientid_error_to_nfsstat(rc); goto out; } return_ok: /* Build the reply */ res_EXCHANGE_ID4_ok.eir_clientid = punconf->cid_clientid; res_EXCHANGE_ID4_ok.eir_sequenceid = punconf->cid_create_session_sequence; #if defined(_USE_FSALMDS) && defined(_USE_FSALDS) res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS | EXCHGID4_FLAG_USE_PNFS_DS | EXCHGID4_FLAG_SUPP_MOVED_REFER; #elif defined(_USE_FSALMDS) res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS | EXCHGID4_FLAG_SUPP_MOVED_REFER; #elif defined(_USE_FSALDS) res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_DS | EXCHGID4_FLAG_SUPP_MOVED_REFER; #elif defined(_USE_DS) res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS | EXCHGID4_FLAG_USE_PNFS_DS | EXCHGID4_FLAG_SUPP_MOVED_REFER; #else res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_SUPP_MOVED_REFER; #endif res_EXCHANGE_ID4_ok.eir_state_protect.spr_how = SP4_NONE; len = strlen(punconf->cid_server_owner); temp = gsh_malloc(len); if(temp == NULL) { LogDebug(component, "Could not allocate memory for so_major_id in response"); /** @todo FSF: not the best way to handle this but keeps from crashing */ len = 0; } else memcpy(temp, punconf->cid_server_owner, len); res_EXCHANGE_ID4_ok.eir_server_owner.so_major_id.so_major_id_len = len; res_EXCHANGE_ID4_ok.eir_server_owner.so_major_id.so_major_id_val = temp; res_EXCHANGE_ID4_ok.eir_server_owner.so_minor_id = 0; len = strlen(punconf->cid_server_scope); temp = gsh_malloc(len); if(temp == NULL) { LogDebug(component, "Could not allocate memory for eir_server_scope in response"); /** @todo FSF: not the best way to handle this but keeps from crashing */ len = 0; } else memcpy(temp, punconf->cid_server_scope, len); res_EXCHANGE_ID4_ok.eir_server_scope.eir_server_scope_len = len; res_EXCHANGE_ID4_ok.eir_server_scope.eir_server_scope_val = temp; res_EXCHANGE_ID4_ok.eir_server_impl_id.eir_server_impl_id_len = 0; res_EXCHANGE_ID4_ok.eir_server_impl_id.eir_server_impl_id_val = NULL; if(isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; sprint_mem(str_verifier, arg_EXCHANGE_ID4.eia_clientowner.co_verifier, NFS4_VERIFIER_SIZE); display_client_id_rec(punconf, str); LogDebug(COMPONENT_CLIENTID, "EXCHANGE_ID reply Verifier=%s %s", str_verifier, str); } res_EXCHANGE_ID4.eir_status = NFS4_OK; out: V(pclient_record->cr_mutex); /* Release our reference to the client record */ dec_client_record_ref(pclient_record); return res_EXCHANGE_ID4.eir_status; } /* nfs41_op_exchange_id */
static bool pseudo_node(char *token, void *arg) { struct node_state *state = (struct node_state *)arg; pseudofs_entry_t *node = NULL; pseudofs_entry_t *new_node = NULL; struct gsh_buffdesc key; char fullpseudopath[MAXPATHLEN + 2]; int j = 0; state->retval = 0; /* start off with no errors */ LogFullDebug(COMPONENT_NFS_V4_PSEUDO, "token %s", token); for (node = state->this_node->sons; node != NULL; node = node->next) { /* Looking for a matching entry */ if (!strcmp(node->name, token)) { /* matched entry is new parent node */ state->this_node = node; return true; } j++; } /* not found so create a new entry */ if (gPseudoFs.last_pseudo_id == (MAX_PSEUDO_ENTRY - 1)) { LogMajor(COMPONENT_NFS_V4_PSEUDO, "Too many nodes in Export_Id %d Path=\"%s\" Pseudo=\"%s\"", state->entry->id, state->entry->fullpath, state->entry->pseudopath); state->retval = ENOMEM; return false; } new_node = gsh_calloc(1, sizeof(pseudofs_entry_t)); if (new_node == NULL) { LogMajor(COMPONENT_NFS_V4_PSEUDO, "Insufficient memory to create pseudo fs node"); state->retval = ENOMEM; return false; } strcpy(new_node->name, token); gPseudoFs.last_pseudo_id++; /** @todo: need to fix this ... */ fullpath(fullpseudopath, new_node, state->this_node, MAXPATHLEN); key = create_pseudo_handle_key(fullpseudopath, (ushort) strlen(fullpseudopath)); new_node->fsopaque = (uint8_t *) key.addr; new_node->pseudo_id = *(uint64_t *) new_node->fsopaque; gPseudoFs.reverse_tab[gPseudoFs.last_pseudo_id] = new_node; new_node->last = new_node; if (isMidDebug(COMPONENT_NFS_V4_PSEUDO)) { char str[256]; sprint_mem(str, new_node->fsopaque, V4_FH_OPAQUE_SIZE); LogMidDebug(COMPONENT_NFS_V4_PSEUDO, "Built pseudofs entry " "index:%u name:%s path:%s handle:%s", gPseudoFs.last_pseudo_id, new_node->name, fullpseudopath, str); } /* Step into the new entry and attach it to the tree */ if (state->this_node->sons == NULL) { state->this_node->sons = new_node; } else { state->this_node->sons->last->next = new_node; state->this_node->sons->last = new_node; } new_node->parent = state->this_node; state->this_node = new_node; return true; }
/** * build the export entry */ fsal_status_t VFSFSAL_BuildExportContext(fsal_export_context_t * context, /* OUT */ fsal_path_t * p_export_path, /* IN */ char *fs_specific_options /* IN */ ) { /* Get the mount point for this lustre FS, * so it can be used for building .lustre/fid paths. */ vfsfsal_export_context_t * p_export_context = (vfsfsal_export_context_t *) context; FILE *fp; struct mntent *p_mnt; char rpath[MAXPATHLEN]; char mntdir[MAXPATHLEN]; char fs_spec[MAXPATHLEN]; char *first_vfs_dir = NULL; char type[MAXNAMLEN+1]; size_t pathlen, outlen; int rc; int mnt_id = 0 ; /* sanity check */ if(p_export_context == NULL) { LogCrit(COMPONENT_FSAL, "NULL mandatory argument passed to %s()", __FUNCTION__); Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_BuildExportContext); } outlen = 0; if(p_export_path != NULL) strncpy(rpath, p_export_path->path, MAXPATHLEN); /* open mnt file */ fp = setmntent(MOUNTED, "r"); if(fp == NULL) { rc = errno; LogCrit(COMPONENT_FSAL, "Error %d in setmntent(%s): %s", rc, MOUNTED, strerror(rc)); Return(posix2fsal_error(rc), rc, INDEX_FSAL_BuildExportContext); } while((p_mnt = getmntent(fp)) != NULL) { /* get the longer path vfs related export that matches export path */ if(p_mnt->mnt_dir != NULL) { pathlen = strlen(p_mnt->mnt_dir); if(first_vfs_dir == NULL) first_vfs_dir = p_mnt->mnt_dir; if((pathlen > outlen) && !strcmp(p_mnt->mnt_dir, "/")) { LogDebug(COMPONENT_FSAL, "Root mountpoint is allowed for matching %s, type=%s, fs=%s", rpath, p_mnt->mnt_type, p_mnt->mnt_fsname); outlen = pathlen; strncpy(mntdir, p_mnt->mnt_dir, MAXPATHLEN); strncpy(type, p_mnt->mnt_type, MAXNAMLEN); strncpy(fs_spec, p_mnt->mnt_fsname, MAXPATHLEN); } /* in other cases, the filesystem must be <mountpoint>/<smthg> or <mountpoint>\0 */ else if((pathlen > outlen) && !strncmp(rpath, p_mnt->mnt_dir, pathlen) && ((rpath[pathlen] == '/') || (rpath[pathlen] == '\0'))) { LogFullDebug(COMPONENT_FSAL, "%s is under mountpoint %s, type=%s, fs=%s", rpath, p_mnt->mnt_dir, p_mnt->mnt_type, p_mnt->mnt_fsname); outlen = pathlen; strncpy(mntdir, p_mnt->mnt_dir, MAXPATHLEN); strncpy(type, p_mnt->mnt_type, MAXNAMLEN); strncpy(fs_spec, p_mnt->mnt_fsname, MAXPATHLEN); } } } if(outlen <= 0) { if(p_export_path == NULL) strncpy(mntdir, first_vfs_dir, MAXPATHLEN); else { LogCrit(COMPONENT_FSAL, "No mount entry matches '%s' in %s", rpath, MOUNTED); endmntent(fp); Return(ERR_FSAL_NOENT, 0, INDEX_FSAL_BuildExportContext); } } /* Save pointer to fsal_staticfsinfo_t in export context */ p_export_context->fe_static_fs_info = &global_fs_info; /* save file descriptor to root of VFS export */ if( ( p_export_context->mount_root_fd = open(mntdir, O_RDONLY | O_DIRECTORY) ) < 0 ) { LogMajor(COMPONENT_FSAL, "FSAL BUILD EXPORT CONTEXT: ERROR: Could not open VFS mount point %s: rc = %d", mntdir, errno); ReturnCode(ERR_FSAL_INVAL, 0); } /* Keep fstype in export_context */ strncpy( p_export_context->fstype, type, MAXNAMLEN ) ; if( !strncmp( type, "xfs", MAXNAMLEN ) ) { LogMajor( COMPONENT_FSAL, "Trying to export XFS filesystem via FSAL_VFS for mount point %s. Use FSAL_XFS instead", mntdir ) ; ReturnCode(ERR_FSAL_INVAL, 0); } p_export_context->root_handle.handle_bytes = VFS_HANDLE_LEN ; if( vfs_fd_to_handle( p_export_context->mount_root_fd, &p_export_context->root_handle, &mnt_id ) ) { LogMajor(COMPONENT_FSAL, "vfs_fd_to_handle: root_path: %s, root_fd=%d, errno=(%d) %s", mntdir, p_export_context->mount_root_fd, errno, strerror(errno)); Return(posix2fsal_error(errno), errno, INDEX_FSAL_BuildExportContext) ; } #ifdef TODO if(isFullDebug(COMPONENT_FSAL)) { char str[1024] ; sprint_mem( str, p_export_context->root_handle.handle ,p_export_context->root_handle.handle_bytes ) ; LogFullDebug(COMPONENT_FSAL, "=====> root Handle: type=%u bytes=%u|%s\n", p_export_context->root_handle.handle_type, p_export_context->root_handle.handle_bytes, str ) ; } #endif Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_BuildExportContext); }
/** * @brief Check and look up the supplied stateid * * This function yields the state for the stateid if it is valid. * * @param[in] stateid Stateid to look up * @param[in] entry Associated file (if any) * @param[out] state Found state * @param[in] data Compound data * @param[in] flags Flags governing special stateids * @param[in] owner_seqid seqid on v4.0 owner * @param[in] check_seqid Whether to validate owner_seqid * @param[in] tag Arbitrary string for logging/debugging * * @return NFSv4 status codes */ nfsstat4 nfs4_Check_Stateid(stateid4 *stateid, cache_entry_t *entry, state_t **state, compound_data_t *data, int flags, seqid4 owner_seqid, bool check_seqid, const char *tag) { uint32_t epoch = 0; uint64_t epoch_low = ServerEpoch & 0xFFFFFFFF; state_t *state2 = NULL; /* string str has to accomodate stateid->other(OTHERSIZE * 2 ), * stateid->seqid(max 10 bytes), * a colon (:) and a terminating null character. */ char str[OTHERSIZE * 2 + 10 + 2]; int32_t diff; clientid4 clientid; nfs_client_id_t *pclientid; int rc; nfsstat4 status; if (isDebug(COMPONENT_STATE)) { sprint_mem(str, (char *)stateid->other, OTHERSIZE); sprintf(str + OTHERSIZE * 2, ":%u", (unsigned int)stateid->seqid); } LogFullDebug(COMPONENT_STATE, "Check %s stateid flags%s%s%s%s%s%s%s", tag, flags & STATEID_SPECIAL_ALL_0 ? " ALL_0" : "", flags & STATEID_SPECIAL_ALL_1 ? " ALL_1" : "", flags & STATEID_SPECIAL_CURRENT ? " CURRENT" : "", flags & STATEID_SPECIAL_CLOSE_40 ? " CLOSE_40" : "", flags & STATEID_SPECIAL_CLOSE_41 ? " CLOSE_41" : "", flags & STATEID_SPECIAL_FREE ? " FREE" : "", flags == 0 ? " NONE" : ""); /* Test for OTHER is all zeros */ if (memcmp(stateid->other, all_zero, OTHERSIZE) == 0) { if (stateid->seqid == 0 && (flags & STATEID_SPECIAL_ALL_0) != 0) { /* All 0 stateid */ LogDebug(COMPONENT_STATE, "Check %s stateid found special all 0 stateid", tag); /** @todo FSF: eventually this may want to return an * actual state for use in temporary locks for I/O. */ data->current_stateid_valid = false; goto success; } if (stateid->seqid == 1 && (flags & STATEID_SPECIAL_CURRENT) != 0) { /* Special current stateid */ LogDebug(COMPONENT_STATE, "Check %s stateid found special 'current' stateid", tag); if (!data->current_stateid_valid) { LogDebug(COMPONENT_STATE, "Check %s stateid STATEID_SPECIAL_CURRENT - current stateid is bad", tag); status = NFS4ERR_BAD_STATEID; goto failure; } /* Copy current stateid in and proceed to checks */ *stateid = data->current_stateid; goto check_it; } LogDebug(COMPONENT_STATE, "Check %s stateid with OTHER all zeros, seqid %u unexpected", tag, (unsigned int)stateid->seqid); status = NFS4ERR_BAD_STATEID; goto failure; } /* Test for OTHER is all ones */ if (memcmp(stateid->other, all_ones, OTHERSIZE) == 0) { /* Test for special all ones stateid */ if (stateid->seqid == seqid_all_one && (flags & STATEID_SPECIAL_ALL_1) != 0) { /* All 1 stateid */ LogDebug(COMPONENT_STATE, "Check %s stateid found special all 1 stateid", tag); /** @todo FSF: eventually this may want to return an * actual state for use in temporary locks for I/O. */ data->current_stateid_valid = false; goto success; } LogDebug(COMPONENT_STATE, "Check %s stateid with OTHER all ones, seqid %u unexpected", tag, (unsigned int)stateid->seqid); status = NFS4ERR_BAD_STATEID; goto failure; } check_it: /* Extract the clientid from the stateid other field */ memcpy(&clientid, stateid->other, sizeof(clientid)); /* Extract the epoch from the clientid */ epoch = clientid >> (clientid4) 32; /* Check if stateid was made from this server instance */ if (epoch != epoch_low) { LogDebug(COMPONENT_STATE, "Check %s stateid found stale stateid %s", tag, str); status = NFS4ERR_STALE_STATEID; goto failure; } /* Try to get the related state */ if (!nfs4_State_Get_Pointer(stateid->other, &state2)) { /* We matched this server's epoch, but could not find the * stateid. Chances are, the client was expired and the state * has all been freed. * * We could use another check here for a BAD stateid */ LogDebug(COMPONENT_STATE, "Check %s stateid could not find state %s", tag, str); /* Try and find the clientid */ rc = nfs_client_id_get_confirmed(clientid, &pclientid); if (rc != CLIENT_ID_SUCCESS) { /* Unknown client id (or other problem), * return that result. */ status = clientid_error_to_nfsstat(rc); goto failure; } if ((flags & (STATEID_SPECIAL_CLOSE_40 | STATEID_SPECIAL_CLOSE_41)) != 0) { /* This is a close with a valid clientid, but invalid * stateid counter. We will assume this is a replayed * close. */ if (data->preserved_clientid != NULL) { /* We don't expect this, but, just in case... * Update and release already reserved lease. */ pthread_mutex_lock(&data->preserved_clientid ->cid_mutex); update_lease(data->preserved_clientid); pthread_mutex_unlock(&data->preserved_clientid ->cid_mutex); data->preserved_clientid = NULL; } /* Check if lease is expired and reserve it */ pthread_mutex_lock(&pclientid->cid_mutex); if (!reserve_lease(pclientid)) { LogDebug(COMPONENT_STATE, "Returning NFS4ERR_EXPIRED"); pthread_mutex_unlock(&pclientid->cid_mutex); status = NFS4ERR_EXPIRED; goto failure; } if ((flags & STATEID_SPECIAL_CLOSE_40) != 0) { /* Just update the lease and leave the reserved * clientid NULL. */ update_lease(pclientid); } else { /* Remember the reserved clientid for the rest * of the compound. */ data->preserved_clientid = pclientid; } pthread_mutex_unlock(&pclientid->cid_mutex); /* Replayed close, it's ok, but stateid doesn't exist */ LogDebug(COMPONENT_STATE, "Check %s stateid is a replayed close", tag); data->current_stateid_valid = false; goto success; } /* Release the clientid reference we just acquired. */ dec_client_id_ref(pclientid); status = NFS4ERR_BAD_STATEID; goto failure; } /* Now, if this lease is not already reserved, reserve it */ if (data->preserved_clientid != state2->state_owner->so_owner.so_nfs4_owner.so_clientrec) { if (data->preserved_clientid != NULL) { /* We don't expect this to happen, but, just in case... * Update and release already reserved lease. */ pthread_mutex_lock(&data->preserved_clientid ->cid_mutex); update_lease(data->preserved_clientid); pthread_mutex_unlock(&data->preserved_clientid ->cid_mutex); data->preserved_clientid = NULL; } /* Check if lease is expired and reserve it */ pthread_mutex_lock(&state2->state_owner->so_owner .so_nfs4_owner.so_clientrec->cid_mutex); if (!reserve_lease (state2->state_owner->so_owner.so_nfs4_owner. so_clientrec)) { LogDebug(COMPONENT_STATE, "Returning NFS4ERR_EXPIRED"); pthread_mutex_unlock(&state2->state_owner->so_owner .so_nfs4_owner.so_clientrec ->cid_mutex); status = NFS4ERR_EXPIRED; goto failure; } data->preserved_clientid = state2->state_owner->so_owner.so_nfs4_owner.so_clientrec; pthread_mutex_unlock(&state2->state_owner->so_owner .so_nfs4_owner.so_clientrec->cid_mutex); } /* Sanity check : Is this the right file ? */ if ((entry != NULL) && (state2->state_entry != entry)) { LogDebug(COMPONENT_STATE, "Check %s stateid found stateid %s has wrong file", tag, str); status = NFS4ERR_BAD_STATEID; goto failure; } /* Whether stateid.seqid may be zero depends on the state type exclusively, See RFC 5661 pp. 161,287-288. */ if ((state2->state_type == STATE_TYPE_LAYOUT) || (stateid->seqid != 0)) { /* Check seqid in stateid */ /** * @todo fsf: maybe change to simple comparison: * stateid->seqid < state2->state_seqid * as good enough and maybe makes pynfs happy. */ diff = stateid->seqid - state2->state_seqid; if (diff < 0) { /* if this is NFSv4.0 and stateid's seqid is one less * than current AND if owner_seqid is current * pass state back to allow replay check */ if ((check_seqid) && ((diff == -1) || ((state2->state_seqid == 1) && (stateid->seqid == seqid_all_one))) && (owner_seqid == state2->state_owner->so_owner.so_nfs4_owner. so_seqid)) { LogDebug(COMPONENT_STATE, "possible replay?"); *state = state2; status = NFS4ERR_REPLAY; goto replay; } /* OLD_STATEID */ LogDebug(COMPONENT_STATE, "Check %s stateid found OLD stateid %s, expected seqid %u", tag, str, (unsigned int)state2->state_seqid); status = NFS4ERR_OLD_STATEID; goto failure; } /* stateid seqid is current and owner seqid is previous, * replay (should be an error condition that did not change * the stateid, no real need to check since the operation * must be the same) */ else if ((diff == 0) && (check_seqid) && (owner_seqid == state2->state_owner->so_owner.so_nfs4_owner. so_seqid)) { LogDebug(COMPONENT_STATE, "possible replay?"); *state = state2; status = NFS4ERR_REPLAY; goto replay; } else if (diff > 0) { /* BAD_STATEID */ LogDebug(COMPONENT_STATE, "Check %s stateid found BAD stateid %s, expected seqid %u", tag, str, (unsigned int)state2->state_seqid); status = NFS4ERR_BAD_STATEID; goto failure; } } if ((flags & STATEID_SPECIAL_FREE) != 0) { switch (state2->state_type) { case STATE_TYPE_LOCK: PTHREAD_RWLOCK_rdlock(&state2->state_entry->state_lock); if (glist_empty (&state2->state_data.lock.state_locklist)) { LogFullDebug(COMPONENT_STATE, "Check %s stateid %s has no locks, ok to free", tag, str); PTHREAD_RWLOCK_unlock(&state2->state_entry-> state_lock); break; } PTHREAD_RWLOCK_unlock(&state2->state_entry->state_lock); /* Fall through for failure */ case STATE_TYPE_NONE: case STATE_TYPE_SHARE: case STATE_TYPE_DELEG: case STATE_TYPE_LAYOUT: LogDebug(COMPONENT_STATE, "Check %s stateid found stateid %s with locks held", tag, str); status = NFS4ERR_LOCKS_HELD; goto failure; } } data->current_stateid_valid = true; LogFullDebug(COMPONENT_STATE, "Check %s stateid found valid stateid %s - %p", tag, str, state2); /* Copy stateid into current for later use */ data->current_stateid = *stateid; data->current_stateid.seqid = state2->state_seqid; success: *state = state2; return NFS4_OK; failure: *state = NULL; replay: data->current_stateid_valid = false; return status; }
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETCLIENTID4args * const arg_SETCLIENTID4 = &op->nfs_argop4_u.opsetclientid; SETCLIENTID4res * const res_SETCLIENTID4 = &resp->nfs_resop4_u.opsetclientid; clientaddr4 * const res_SETCLIENTID4_INUSE = &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using; char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; struct display_buffer dspbuf_verifier = { sizeof(str_verifier), str_verifier, str_verifier}; char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; struct display_buffer dspbuf_client = { sizeof(str_client), str_client, str_client}; const char *str_client_addr = "(unknown)"; /* The clientid4 broken down into fields */ char str_clientid4[DISPLAY_CLIENTID_SIZE]; /* Display buffer for clientid4 */ struct display_buffer dspbuf_clientid4 = { sizeof(str_clientid4), str_clientid4, str_clientid4}; nfs_client_record_t *client_record; nfs_client_id_t *conf; nfs_client_id_t *unconf; clientid4 clientid; verifier4 verifier; int rc; resp->resop = NFS4_OP_SETCLIENTID; if (data->minorversion > 0) { res_SETCLIENTID4->status = NFS4ERR_NOTSUPP; return res_SETCLIENTID4->status; } if (op_ctx->client != NULL) str_client_addr = op_ctx->client->hostaddr_str; if (isDebug(COMPONENT_CLIENTID)) { display_opaque_value(&dspbuf_client, arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len); display_opaque_bytes(&dspbuf_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); } else { str_client[0] = '\0'; str_verifier[0] = '\0'; } LogDebug(COMPONENT_CLIENTID, "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u", str_client_addr, str_client, str_verifier, arg_SETCLIENTID4->callback.cb_program, arg_SETCLIENTID4->callback.cb_location.r_addr, arg_SETCLIENTID4->callback.cb_location.r_netid, arg_SETCLIENTID4->callback_ident); /* Do we already have one or more records for client id (x)? */ client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len, 0, 0); if (client_record == NULL) { /* Some major failure */ LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed"); res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT; return res_SETCLIENTID4->status; } /* The following checks are based on RFC3530bis draft 16 * * This attempts to implement the logic described in * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE * 1, CASE 2, CASE 3, CASE 4, and CASE 5. */ PTHREAD_MUTEX_lock(&client_record->cr_mutex); if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_record(&dspbuf, client_record); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } conf = client_record->cr_confirmed_rec; if (conf != NULL) { bool credmatch; /* Need a reference to the confirmed record for below */ inc_client_id_ref(conf); clientid = conf->cid_clientid; display_clientid(&dspbuf_clientid4, clientid); credmatch = nfs_compare_clientcred(&conf->cid_credential, &data->credential) && op_ctx->client != NULL && conf->gsh_client != NULL && op_ctx->client == conf->gsh_client; /* Only reject if the principal doesn't match and the * clientid has live state associated. Per RFC 7530 * Section 9.1.2. Server Release of Client ID. */ if (!credmatch && clientid_has_state(conf)) { /* CASE 1: * * Confirmed record exists and not the same principal */ if (isDebug(COMPONENT_CLIENTID)) { char *confirmed_addr = "(unknown)"; if (conf->gsh_client != NULL) confirmed_addr = conf->gsh_client->hostaddr_str; LogDebug(COMPONENT_CLIENTID, "Confirmed ClientId %s->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", str_clientid4, str_client, confirmed_addr); } res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE; res_SETCLIENTID4_INUSE->r_netid = (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc] .netid; res_SETCLIENTID4_INUSE->r_addr = gsh_strdup(conf->cid_cb.v40.cb_client_r_addr); /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); goto out; } /* Check if confirmed record is for (v, x, c, l, s) */ if (credmatch && memcmp(arg_SETCLIENTID4->client.verifier, conf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) { /* CASE 2: * * A confirmed record exists for this long * form client id and verifier. * * Consider this to be a possible update of * the call-back information. * * Remove any pre-existing unconfirmed record * for (v, x, c). * * Return the same short form client id (c), * but a new setclientid_confirm verifier (t). */ LogFullDebug(COMPONENT_CLIENTID, "Update ClientId %s->%s", str_clientid4, str_client); new_clientid_verifier(verifier); } else { /* Must be CASE 3 or CASE 4 * * Confirmed record is for (u, x, c, l, s). * * These are actually the same, doesn't really * matter if an unconfirmed record exists or * not. Any existing unconfirmed record will * be removed and a new unconfirmed record * added. * * Return a new short form clientid (d) and a * new setclientid_confirm verifier (t). (Note * the spec calls the values e and r for CASE * 4). */ LogFullDebug(COMPONENT_CLIENTID, "Replace ClientId %s->%s", str_clientid4, str_client); clientid = new_clientid(); new_clientid_verifier(verifier); } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); } else { /* CASE 5: * * * Remove any existing unconfirmed record. * * Return a new short form clientid (d) and a new * setclientid_confirm verifier (t). */ clientid = new_clientid(); display_clientid(&dspbuf_clientid4, clientid); LogFullDebug(COMPONENT_CLIENTID, "New client %s", str_clientid4); new_clientid_verifier(verifier); } /* At this point, no matter what the case was above, we should * remove any pre-existing unconfirmed record. */ unconf = client_record->cr_unconfirmed_rec; if (unconf != NULL) { /* Delete the unconfirmed clientid record. Because we * have the cr_mutex, we have won any race to deal * with this clientid record (whether we raced with a * SETCLIENTID_CONFIRM or the reaper thread (if either * of those operations had won the race, * cr_punconfirmed_id would have been NULL). */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "Replacing %s", str); } /* unhash the clientid record */ remove_unconfirmed_client_id(unconf); unconf = NULL; } /* Now we can proceed to build the new unconfirmed record. We * have determined the clientid and setclientid_confirm values * above. */ unconf = create_client_id(clientid, client_record, &data->credential, 0); if (unconf == NULL) { /* Error already logged, return */ res_SETCLIENTID4->status = NFS4ERR_RESOURCE; goto out; } if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr, arg_SETCLIENTID4->callback.cb_location.r_addr, sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) { LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long", arg_SETCLIENTID4->callback.cb_location.r_addr); res_SETCLIENTID4->status = NFS4ERR_INVAL; goto out; } nfs_set_client_location(unconf, &arg_SETCLIENTID4->callback.cb_location); memcpy(unconf->cid_incoming_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier)); unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program; unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident; rc = nfs_client_id_insert(unconf); if (rc != CLIENT_ID_SUCCESS) { /* Record is already freed, return. */ res_SETCLIENTID4->status = clientid_error_to_nfsstat_no_expire(rc); goto out; } if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE); display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s", str_verifier, str); } res_SETCLIENTID4->status = NFS4_OK; res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid; memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm, &verifier, NFS4_VERIFIER_SIZE); out: PTHREAD_MUTEX_unlock(&client_record->cr_mutex); /* Release our reference to the client record */ dec_client_record_ref(client_record); return res_SETCLIENTID4->status; }
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETCLIENTID4args * const arg_SETCLIENTID4 = &op->nfs_argop4_u.opsetclientid; SETCLIENTID4res * const res_SETCLIENTID4 = &resp->nfs_resop4_u.opsetclientid; clientaddr4 * const res_SETCLIENTID4_INUSE = &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using; char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; char str_client_addr[SOCK_NAME_MAX + 1]; nfs_client_record_t *client_record; nfs_client_id_t *conf; nfs_client_id_t *unconf; clientid4 clientid; verifier4 verifier; sockaddr_t client_addr; int rc; resp->resop = NFS4_OP_SETCLIENTID; if (data->minorversion > 0) { res_SETCLIENTID4->status = NFS4ERR_NOTSUPP; return res_SETCLIENTID4->status; } copy_xprt_addr(&client_addr, data->req->rq_xprt); if (isDebug(COMPONENT_CLIENTID)) { sprint_sockip(&client_addr, str_client_addr, sizeof(str_client_addr)); DisplayOpaqueValue(arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len, str_client); sprint_mem(str_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); } LogDebug(COMPONENT_CLIENTID, "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u", str_client_addr, str_client, str_verifier, arg_SETCLIENTID4->callback.cb_program, arg_SETCLIENTID4->callback.cb_location.r_addr, arg_SETCLIENTID4->callback.cb_location.r_netid, arg_SETCLIENTID4->callback_ident); /* Do we already have one or more records for client id (x)? */ client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len, 0, 0); if (client_record == NULL) { /* Some major failure */ LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed"); res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT; return res_SETCLIENTID4->status; } /* The following checks are based on RFC3530bis draft 16 * * This attempts to implement the logic described in * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE * 1, CASE 2, CASE 3, CASE 4, and CASE 5. */ pthread_mutex_lock(&client_record->cr_mutex); if (isFullDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_record(client_record, str); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_confirmed_rec=%p " "cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } conf = client_record->cr_confirmed_rec; if (conf != NULL) { /* Need a reference to the confirmed record for below */ inc_client_id_ref(conf); if (!nfs_compare_clientcred(&conf->cid_credential, &data->credential) || !cmp_sockaddr(&conf->cid_client_addr, &client_addr, true)) { /* CASE 1: * * Confirmed record exists and not the same principal */ if (isDebug(COMPONENT_CLIENTID)) { char confirmed_addr[SOCK_NAME_MAX + 1]; sprint_sockip(&conf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr)); LogDebug(COMPONENT_CLIENTID, "Confirmed ClientId %" PRIx64 "->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", conf->cid_clientid, str_client, confirmed_addr); } res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE; res_SETCLIENTID4_INUSE->r_netid = (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc] .netid; res_SETCLIENTID4_INUSE->r_addr = gsh_strdup(conf->cid_cb.v40.cb_client_r_addr); /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); goto out; } /* Check if confirmed record is for (v, x, c, l, s) */ if (memcmp (arg_SETCLIENTID4->client.verifier, conf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) { /* CASE 2: * * A confirmed record exists for this long * form client id and verifier. * * Consider this to be a possible update of * the call-back information. * * Remove any pre-existing unconfirmed record * for (v, x, c). * * Return the same short form client id (c), * but a new setclientid_confirm verifier (t). */ LogFullDebug(COMPONENT_CLIENTID, "Update ClientId %" PRIx64 "->%s", conf->cid_clientid, str_client); clientid = conf->cid_clientid; new_clientid_verifier(verifier); } else { /* Must be CASE 3 or CASE 4 * * Confirmed record is for (u, x, c, l, s). * * These are actually the same, doesn't really * matter if an unconfirmed record exists or * not. Any existing unconfirmed record will * be removed and a new unconfirmed record * added. * * Return a new short form clientid (d) and a * new setclientid_confirm verifier (t). (Note * the spec calls the values e and r for CASE * 4). */ LogFullDebug(COMPONENT_CLIENTID, "Replace ClientId %" PRIx64 "->%s", conf->cid_clientid, str_client); clientid = new_clientid(); new_clientid_verifier(verifier); } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); } else { /* CASE 5: * * * Remove any existing unconfirmed record. * * Return a new short form clientid (d) and a new * setclientid_confirm verifier (t). */ LogFullDebug(COMPONENT_CLIENTID, "New client"); clientid = new_clientid(); new_clientid_verifier(verifier); } /* At this point, no matter what the case was above, we should * remove any pre-existing unconfirmed record. */ unconf = client_record->cr_unconfirmed_rec; if (unconf != NULL) { /* Delete the unconfirmed clientid record. Because we * have the cr_mutex, we have won any race to deal * with this clientid record (whether we raced with a * SETCLIENTID_CONFIRM or the reaper thread (if either * of those operations had won the race, * cr_punconfirmed_id would have been NULL). */ if (isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_id_rec(unconf, str); LogDebug(COMPONENT_CLIENTID, "Replacing %s", str); } /* unhash the clientid record */ remove_unconfirmed_client_id(unconf); unconf = NULL; } /* Now we can proceed to build the new unconfirmed record. We * have determined the clientid and setclientid_confirm values * above. */ unconf = create_client_id(clientid, client_record, &client_addr, &data->credential, 0); if (unconf == NULL) { /* Error already logged, return */ res_SETCLIENTID4->status = NFS4ERR_RESOURCE; goto out; } if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr, arg_SETCLIENTID4->callback.cb_location.r_addr, sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) { LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long", arg_SETCLIENTID4->callback.cb_location.r_addr); res_SETCLIENTID4->status = NFS4ERR_INVAL; goto out; } nfs_set_client_location(unconf, &arg_SETCLIENTID4->callback.cb_location); memcpy(unconf->cid_incoming_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier)); unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program; unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident; rc = nfs_client_id_insert(unconf); if (rc != CLIENT_ID_SUCCESS) { /* Record is already freed, return. */ res_SETCLIENTID4->status = clientid_error_to_nfsstat(rc); goto out; } if (isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE); display_client_id_rec(unconf, str); LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s", str_verifier, str); } res_SETCLIENTID4->status = NFS4_OK; res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid; memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm, &verifier, NFS4_VERIFIER_SIZE); out: pthread_mutex_unlock(&client_record->cr_mutex); /* Release our reference to the client record */ dec_client_record_ref(client_record); return res_SETCLIENTID4->status; }
void sprint_fhandle3(char *str, nfs_fh3 *fh) { char *tmp = str + sprintf(str, "File Handle V3: Len=%u ", fh->data.data_len); sprint_mem(tmp, fh->data.data_val, fh->data.data_len); } /* sprint_fhandle3 */