/**
 * @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);
	}
}
示例#2
0
/**
 * @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);
}