/** * @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); } }
/** * @brief Create a new delegation state then get the delegation. * * Create a new delegation state for this client and file. * Then attempt to get a LEASE lock to delegate the file * according to whether the client opened READ or READ/WRITE. * * @note state_lock must be held for WRITE * * @param[in] data Compound data for this request * @param[in] op NFS arguments for the request * @param[in] open_state Open state for the inode to be delegated. * @param[in] openowner Open owner of the open state. * @param[in] client Client that will own the delegation. * @param[in/out] resok Delegation attempt result to be returned to client. * @param[in] prerecall flag for reclaims. */ static void get_delegation(compound_data_t *data, OPEN4args *args, state_t *open_state, state_owner_t *openowner, nfs_client_id_t *client, OPEN4resok *resok, bool prerecall) { state_status_t state_status; union state_data state_data; open_delegation_type4 deleg_type; state_owner_t *clientowner = &client->cid_owner; struct state_refer refer; state_t *new_state = NULL; struct state_hdl *ostate; open_write_delegation4 *writeres = &resok->delegation.open_delegation4_u.write; open_read_delegation4 *readres = &resok->delegation.open_delegation4_u.read; open_none_delegation4 *whynone = &resok->delegation.open_delegation4_u.od_whynone; ostate = data->current_obj->state_hdl; if (!ostate) { LogFullDebug(COMPONENT_NFS_V4_LOCK, "Could not get file state"); whynone->ond_why = WND4_RESOURCE; return; } /* Record the sequence info */ if (data->minorversion > 0) { memcpy(refer.session, data->session->session_id, sizeof(sessionid4)); refer.sequence = data->sequence; refer.slot = data->slot; } if (args->share_access & OPEN4_SHARE_ACCESS_WRITE) { deleg_type = OPEN_DELEGATE_WRITE; } else { assert(args->share_access & OPEN4_SHARE_ACCESS_READ); deleg_type = OPEN_DELEGATE_READ; } LogDebug(COMPONENT_STATE, "Attempting to grant %s delegation", deleg_type == OPEN_DELEGATE_WRITE ? "WRITE" : "READ"); init_new_deleg_state(&state_data, deleg_type, client); /* Add the delegation state */ state_status = state_add_impl(data->current_obj, STATE_TYPE_DELEG, &state_data, clientowner, &new_state, data->minorversion > 0 ? &refer : NULL); if (state_status != STATE_SUCCESS) { LogDebug(COMPONENT_NFS_V4_LOCK, "get delegation call failed to add state with status %s", state_err_str(state_status)); whynone->ond_why = WND4_RESOURCE; return; } new_state->state_seqid++; LogFullDebugOpaque(COMPONENT_STATE, "delegation state added, stateid: %s", 100, new_state->stateid_other, OTHERSIZE); /* acquire_lease_lock() gets the delegation from FSAL */ state_status = acquire_lease_lock(ostate, clientowner, new_state); if (state_status != STATE_SUCCESS) { if (args->claim.claim != CLAIM_PREVIOUS) { LogDebug(COMPONENT_NFS_V4_LOCK, "get delegation call added state but failed to lock with status %s", state_err_str(state_status)); state_del_locked(new_state); dec_state_t_ref(new_state); if (state_status == STATE_LOCK_CONFLICT) whynone->ond_why = WND4_CONTENTION; else whynone->ond_why = WND4_RESOURCE; return; } prerecall = true; } resok->delegation.delegation_type = deleg_type; ostate->file.fdeleg_stats.fds_deleg_type = deleg_type; if (deleg_type == OPEN_DELEGATE_WRITE) { nfs_space_limit4 *space_limit = &writeres->space_limit; space_limit->limitby = NFS_LIMIT_SIZE; space_limit->nfs_space_limit4_u.filesize = DELEG_SPACE_LIMIT_FILESZ; COPY_STATEID(&writeres->stateid, new_state); writeres->recall = prerecall; get_deleg_perm(&writeres->permissions, deleg_type); } else { assert(deleg_type == OPEN_DELEGATE_READ); COPY_STATEID(&readres->stateid, new_state); readres->recall = prerecall; get_deleg_perm(&readres->permissions, deleg_type); } if (isDebug(COMPONENT_NFS_V4_LOCK)) { char str1[LOG_BUFF_LEN / 2] = "\0"; char str2[LOG_BUFF_LEN / 2] = "\0"; struct display_buffer dspbuf1 = {sizeof(str1), str1, str1}; struct display_buffer dspbuf2 = {sizeof(str2), str2, str2}; display_nfs4_owner(&dspbuf1, openowner); display_nfs4_owner(&dspbuf2, clientowner); LogDebug(COMPONENT_NFS_V4_LOCK, "get delegation openowner %s clientowner %s status %s", str1, str2, state_err_str(state_status)); } dec_state_t_ref(new_state); }