/** * @brief Compare to stateids * * @param[in] buff1 One key * @param[in] buff2 Another key * * @retval 0 if equal. * @retval 1 if not equal. */ int compare_state_id(struct gsh_buffdesc *buff1, struct gsh_buffdesc *buff2) { if (isFullDebug(COMPONENT_STATE)) { char str1[OTHERSIZE * 2 + 32], str2[OTHERSIZE * 2 + 32]; display_stateid_other(buff1->addr, str1); display_stateid_other(buff2->addr, str2); if (isDebug(COMPONENT_HASHTABLE)) LogFullDebug(COMPONENT_STATE, "{%s} vs {%s}", str1, str2); } return memcmp(buff1->addr, buff2->addr, OTHERSIZE); } /* compare_state_id */
/** * @brief adds a new state to a file * * This version of the function does not take the state lock on the * entry. It exists to allow callers to integrate state into a larger * operation. * * The caller may have already allocated a state, in which case state * need not be NULL. * * @note state_lock MUST be held for write * * @param[in,out] obj file to operate on * @param[in] state_type State to be defined * @param[in] state_data Data related to this state * @param[in] owner_input Related open_owner * @param[in,out] state The new state * @param[in] refer Reference to compound creating state * * @return Operation status */ state_status_t state_add_impl(struct fsal_obj_handle *obj, enum state_type state_type, union state_data *state_data, state_owner_t *owner_input, state_t **state, struct state_refer *refer) { state_t *pnew_state = *state; struct state_hdl *ostate = obj->state_hdl; char str[DISPLAY_STATEID_OTHER_SIZE]; struct display_buffer dspbuf = {sizeof(str), str, str}; bool str_valid = false; bool got_export_ref = false; state_status_t status = 0; bool mutex_init = false; struct state_t *openstate = NULL; struct gsh_buffdesc fh_desc; if (isFullDebug(COMPONENT_STATE) && pnew_state != NULL) { display_stateid(&dspbuf, pnew_state); LogFullDebug(COMPONENT_STATE, "pnew_state=%s", str); display_reset_buffer(&dspbuf); } /* Attempt to get a reference to the export. */ if (!export_ready(op_ctx->ctx_export)) { /* If we could not get a reference, return stale. * Release attr_lock */ LogDebug(COMPONENT_STATE, "Stale export"); status = STATE_ESTALE; goto errout; } get_gsh_export_ref(op_ctx->ctx_export); got_export_ref = true; if (pnew_state == NULL) { if (state_type == STATE_TYPE_LOCK) openstate = state_data->lock.openstate; pnew_state = op_ctx->fsal_export->exp_ops.alloc_state( op_ctx->fsal_export, state_type, openstate); } PTHREAD_MUTEX_init(&pnew_state->state_mutex, NULL); mutex_init = true; /* Add the stateid.other, this will increment cid_stateid_counter */ nfs4_BuildStateId_Other(owner_input->so_owner.so_nfs4_owner. so_clientrec, pnew_state->stateid_other); /* Set the type and data for this state */ memcpy(&(pnew_state->state_data), state_data, sizeof(*state_data)); pnew_state->state_type = state_type; pnew_state->state_seqid = 0; /* will be incremented to 1 later */ pnew_state->state_refcount = 2; /* sentinel plus returned ref */ if (refer) pnew_state->state_refer = *refer; if (isFullDebug(COMPONENT_STATE)) { display_stateid_other(&dspbuf, pnew_state->stateid_other); str_valid = true; LogFullDebug(COMPONENT_STATE, "About to call nfs4_State_Set for %s", str); } glist_init(&pnew_state->state_list); /* We need to initialize state_owner, state_export, and state_obj now so * that the state can be indexed by owner/entry. We don't insert into * lists and take references yet since no one else can see this state * until we are completely done since we hold the state_lock. Might as * well grab export now also... */ pnew_state->state_export = op_ctx->ctx_export; pnew_state->state_owner = owner_input; fh_desc.addr = &pnew_state->state_obj.digest; fh_desc.len = sizeof(pnew_state->state_obj.digest); obj->obj_ops.handle_digest(obj, FSAL_DIGEST_NFSV4, &fh_desc); pnew_state->state_obj.len = fh_desc.len; /* Add the state to the related hashtable */ if (!nfs4_State_Set(pnew_state)) { if (!str_valid) display_stateid_other(&dspbuf, pnew_state->stateid_other); LogCrit(COMPONENT_STATE, "Can't create a new state id %s for the obj %p (F)", str, obj); /* Return STATE_MALLOC_ERROR since most likely the * nfs4_State_Set failed to allocate memory. */ status = STATE_MALLOC_ERROR; goto errout; } /* Each of the following blocks takes the state_mutex and releases it * because we always want state_mutex to be the last lock taken. * * NOTE: We don't have to worry about state_del/state_del_locked being * called in the midst of things because the state_lock is held. */ /* Attach this to an export */ PTHREAD_RWLOCK_wrlock(&op_ctx->ctx_export->lock); PTHREAD_MUTEX_lock(&pnew_state->state_mutex); glist_add_tail(&op_ctx->ctx_export->exp_state_list, &pnew_state->state_export_list); PTHREAD_MUTEX_unlock(&pnew_state->state_mutex); PTHREAD_RWLOCK_unlock(&op_ctx->ctx_export->lock); /* Add state to list for file */ PTHREAD_MUTEX_lock(&pnew_state->state_mutex); glist_add_tail(&ostate->file.list_of_states, &pnew_state->state_list); PTHREAD_MUTEX_unlock(&pnew_state->state_mutex); /* Add state to list for owner */ PTHREAD_MUTEX_lock(&owner_input->so_mutex); PTHREAD_MUTEX_lock(&pnew_state->state_mutex); inc_state_owner_ref(owner_input); glist_add_tail(&owner_input->so_owner.so_nfs4_owner.so_state_list, &pnew_state->state_owner_list); PTHREAD_MUTEX_unlock(&pnew_state->state_mutex); PTHREAD_MUTEX_unlock(&owner_input->so_mutex); #ifdef DEBUG_SAL PTHREAD_MUTEX_lock(&all_state_v4_mutex); glist_add_tail(&state_v4_all, &pnew_state->state_list_all); PTHREAD_MUTEX_unlock(&all_state_v4_mutex); #endif if (pnew_state->state_type == STATE_TYPE_DELEG && pnew_state->state_data.deleg.sd_type == OPEN_DELEGATE_WRITE) ostate->file.write_delegated = true; /* Copy the result */ *state = pnew_state; if (str_valid) LogFullDebug(COMPONENT_STATE, "Add State: %p: %s", pnew_state, str); /* Regular exit */ status = STATE_SUCCESS; return status; errout: if (mutex_init) PTHREAD_MUTEX_destroy(&pnew_state->state_mutex); if (pnew_state != NULL) { /* Make sure the new state is closed (may have been passed in * with file open). */ (void) obj->obj_ops.close2(obj, pnew_state); pnew_state->state_exp->exp_ops.free_state(pnew_state); } if (got_export_ref) put_gsh_export(op_ctx->ctx_export); *state = NULL; return status; } /* state_add */
/** * @brief Display a stateid other in the hash table * * @param[in] buff The key * @param[out] str Output buffer * * @return Length of output string. */ int display_state_id_key(struct gsh_buffdesc *buff, char *str) { return display_stateid_other(buff->addr, str); }