/** * @brief Compare two NFSv4 owners in the hash table * * @param[in] buff1 One key * @param[in] buff2 Another owner * * @retval 0 on equality. * @retval 1 on inequality. */ int compare_nfs4_owner_key(struct gsh_buffdesc *buff1, struct gsh_buffdesc *buff2) { state_owner_t *pkey1 = buff1->addr; state_owner_t *pkey2 = buff2->addr; if (isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE)) { char str1[HASHTABLE_DISPLAY_STRLEN]; char str2[HASHTABLE_DISPLAY_STRLEN]; DisplayOwner(pkey1, str1); DisplayOwner(pkey2, str2); if (isDebug(COMPONENT_HASHTABLE)) LogFullDebug(COMPONENT_STATE, "{%s} vs {%s}", str1, str2); } if (pkey1 == NULL || pkey2 == NULL) return 1; if (pkey1->so_type != pkey2->so_type) return 1; return compare_nfs4_owner(pkey1, pkey2); }
state_owner_t *create_nfs4_owner(state_nfs4_owner_name_t * pname, nfs_client_id_t * pclientid, state_owner_type_t type, state_owner_t * related_owner, unsigned int init_seqid) { state_owner_t * powner; state_nfs4_owner_name_t * powner_name; /* This lock owner is not known yet, allocated and set up a new one */ powner = pool_alloc(state_owner_pool, NULL); if(powner == NULL) return NULL; powner_name = pool_alloc(state_nfs4_owner_name_pool, NULL); if(powner_name == NULL) { pool_free(state_owner_pool, powner); return NULL; } *powner_name = *pname; /* set up the content of the open_owner */ memset(powner, 0, sizeof(*powner)); powner->so_type = type; powner->so_owner.so_nfs4_owner.so_seqid = init_seqid; powner->so_owner.so_nfs4_owner.so_related_owner = related_owner; powner->so_owner.so_nfs4_owner.so_clientid = pname->son_clientid; powner->so_owner.so_nfs4_owner.so_pclientid = pclientid; powner->so_owner_len = pname->son_owner_len; powner->so_owner.so_nfs4_owner.so_resp.resop = NFS4_OP_ILLEGAL; powner->so_owner.so_nfs4_owner.so_args.argop = NFS4_OP_ILLEGAL; powner->so_refcount = 1; #if 0 /* WAITING FOR COMMUNITY FIX */ /* setting lock owner confirmed */ if ( type == STATE_LOCK_OWNER_NFSV4) powner->so_owner.so_nfs4_owner.so_confirmed = 1; #endif init_glist(&powner->so_lock_list); init_glist(&powner->so_owner.so_nfs4_owner.so_state_list); memcpy(powner->so_owner_val, pname->son_owner_val, pname->son_owner_len); powner->so_owner_val[powner->so_owner_len] = '\0'; if(pthread_mutex_init(&powner->so_mutex, NULL) == -1) { pool_free(state_owner_pool, powner); pool_free(state_nfs4_owner_name_pool, powner_name); return NULL; } if(!nfs4_owner_Set(powner_name, powner)) { pool_free(state_owner_pool, powner); pool_free(state_nfs4_owner_name_pool, powner_name); return NULL; } if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; DisplayOwner(powner, str); LogFullDebug(COMPONENT_STATE, "New Owner %s", str); } /* Increment refcount on related owner */ if(related_owner != NULL) inc_state_owner_ref(related_owner); P(pclientid->cid_mutex); if (type == STATE_OPEN_OWNER_NFSV4) { /* If open owner, add to clientid lock owner list */ powner->so_refcount++; glist_add_tail(&pclientid->cid_openowners, &powner->so_owner.so_nfs4_owner.so_perclient); } else if(type == STATE_LOCK_OWNER_NFSV4) { /* If lock owner, add to clientid open owner list */ powner->so_refcount++; glist_add_tail(&pclientid->cid_lockowners, &powner->so_owner.so_nfs4_owner.so_perclient); } /* Increment reference count for clientid record */ inc_client_id_ref(pclientid); V(pclientid->cid_mutex); return powner; }
/** * @brief Check NFS4 request for valid seqid for replay, next request, or BAD_SEQID. * * Returns true if the request is the next seqid. If the request is a * replay, copies the saved response and returns false. Otherwise, * sets status to NFS4ERR_BAD_SEQID and returns false. * * In either case, on a false return, the caller should send the * resulting response back to the client. * * @param[in] owner Owner to check * @param[in] seqid Seqid to check * @param[in] args Arguments of operation * @param[in] data Compound data * @param[out] resp Cached request, if replay * @param[in] tag Arbitrary string for logging/debugging * * @retval true if the caller should process the operation. * @retval false if the caller should immediately return the provides response. */ bool Check_nfs4_seqid(state_owner_t *owner, seqid4 seqid, nfs_argop4 *args, cache_entry_t *entry, nfs_resop4 *resp, const char *tag) { seqid4 next; char str[HASHTABLE_DISPLAY_STRLEN]; /* Check if any owner to verify seqid against */ if (owner == NULL) { LogFullDebug(COMPONENT_STATE, "%s: Unknown owner doesn't have saved seqid, req seqid %u", tag, seqid); return true; } if (isDebug(COMPONENT_STATE)) DisplayOwner(owner, str); /* If this is a new state owner, client may start with any seqid */ if (owner->so_owner.so_nfs4_owner.so_last_entry == NULL) { LogFullDebug(COMPONENT_STATE, "%s: New {%s} doesn't have saved seqid, req seqid %u", tag, str, seqid); return true; } /* Check for valid next seqid */ next = owner->so_owner.so_nfs4_owner.so_seqid + 1; LogFullDebug(COMPONENT_STATE, "%s: Check {%s} next %u req seqid %u", tag, str, next, seqid); if (seqid == next) return true; /* All NFS4 responses have the status in the same place, so use any to * set NFS4ERR_BAD_SEQID */ resp->nfs_resop4_u.oplock.status = NFS4ERR_BAD_SEQID; /* Now check for valid replay */ if (owner->so_owner.so_nfs4_owner.so_seqid != seqid) { LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay), expected seqid for {%s}, returning NFS4ERR_BAD_SEQID", tag, seqid, str); return false; } if (args->argop != owner->so_owner.so_nfs4_owner.so_args.argop) { LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay - not same op), expected seqid for {%s}, returning NFS4ERR_BAD_SEQID", tag, seqid, str); return false; } if (owner->so_owner.so_nfs4_owner.so_last_entry != entry) { LogDebug(COMPONENT_STATE, "%s: Invalid seqid %u in request (not replay - wrong file), expected seqid for {%s}, returning NFS4ERR_BAD_SEQID", tag, seqid, str); return false; } /** @todo FSF: add more checks here... */ LogDebug(COMPONENT_STATE, "%s: Copying saved response for seqid %u into {%s}", tag, seqid, str); /* Copy the saved response and tell caller to use it */ nfs4_Compound_CopyResOne(resp, &owner->so_owner.so_nfs4_owner.so_resp); return false; }
/** * @brief Create an NFSv4 state owner * * @param[in] name Owner name * @param[in] clientid Client record * @param[in] type Owner type * @param[in] related_owner For lock owners, the related open owner * @param[in] init_seqid The starting seqid (for NFSv4.0) * @param[out] pisnew Whether the owner actually is new * @param[in] care Care flag (to unify v3/v4 owners?) * * @return A new state owner or NULL. */ state_owner_t *create_nfs4_owner(state_nfs4_owner_name_t *name, nfs_client_id_t *clientid, state_owner_type_t type, state_owner_t *related_owner, unsigned int init_seqid, bool_t *pisnew, care_t care) { state_owner_t key; state_owner_t *owner; bool_t isnew; /* set up the content of the open_owner */ memset(&key, 0, sizeof(key)); key.so_type = type; key.so_owner.so_nfs4_owner.so_seqid = init_seqid; key.so_owner.so_nfs4_owner.so_related_owner = related_owner; key.so_owner.so_nfs4_owner.so_clientid = clientid->cid_clientid; key.so_owner.so_nfs4_owner.so_clientrec = clientid; key.so_owner_len = name->son_owner_len; key.so_owner_val = name->son_owner_val; key.so_owner.so_nfs4_owner.so_resp.resop = NFS4_OP_ILLEGAL; key.so_owner.so_nfs4_owner.so_args.argop = NFS4_OP_ILLEGAL; key.so_refcount = 1; #if 0 /* WAITING FOR COMMUNITY FIX */ /* setting lock owner confirmed */ if (type == STATE_LOCK_OWNER_NFSV4) key.so_owner.so_nfs4_owner.so_confirmed = 1; #endif owner = get_state_owner(care, &key, init_nfs4_owner, &isnew); if (owner != NULL && related_owner != NULL) { pthread_mutex_lock(&owner->so_mutex); /* Related owner already exists. */ if (owner->so_owner.so_nfs4_owner.so_related_owner == NULL) { /* Attach related owner to owner now that we know it. */ inc_state_owner_ref(related_owner); owner->so_owner.so_nfs4_owner.so_related_owner = related_owner; } else if (owner->so_owner.so_nfs4_owner.so_related_owner != related_owner) { char str1[HASHTABLE_DISPLAY_STRLEN]; char str2[HASHTABLE_DISPLAY_STRLEN]; DisplayOwner(related_owner, str1); DisplayOwner(owner, str1); LogCrit(COMPONENT_NFS_V4_LOCK, "Related {%s} doesn't match for {%s}", str1, str2); pthread_mutex_unlock(&owner->so_mutex); /* Release the reference to the owner. */ dec_state_owner_ref(owner); return NULL; } pthread_mutex_unlock(&owner->so_mutex); } if (!isnew && owner != NULL && pisnew != NULL) { if (isDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; DisplayOwner(owner, str); LogDebug(COMPONENT_STATE, "Previously known owner {%s} is being reused", str); } } if (pisnew != NULL) *pisnew = isnew; return owner; }
state_owner_t *create_nfs4_owner(cache_inode_client_t * pclient, state_nfs4_owner_name_t * pname, state_owner_type_t type, state_owner_t * related_owner, unsigned int init_seqid) { state_owner_t * powner; state_nfs4_owner_name_t * powner_name; /* This lock owner is not known yet, allocated and set up a new one */ GetFromPool(powner, &pclient->pool_state_owner, state_owner_t); if(powner == NULL) return NULL; GetFromPool(powner_name, &pclient->pool_nfs4_owner_name, state_nfs4_owner_name_t); if(powner_name == NULL) { ReleaseToPool(powner, &pclient->pool_state_owner); return NULL; } *powner_name = *pname; /* set up the content of the open_owner */ memset(powner, 0, sizeof(*powner)); powner->so_type = type; powner->so_owner.so_nfs4_owner.so_seqid = init_seqid; powner->so_owner.so_nfs4_owner.so_related_owner = related_owner; powner->so_owner.so_nfs4_owner.so_clientid = pname->son_clientid; powner->so_owner_len = pname->son_owner_len; powner->so_owner.so_nfs4_owner.so_resp.resop = NFS4_OP_ILLEGAL; powner->so_owner.so_nfs4_owner.so_args.argop = NFS4_OP_ILLEGAL; powner->so_refcount = 1; init_glist(&powner->so_lock_list); memcpy(powner->so_owner_val, pname->son_owner_val, pname->son_owner_len); powner->so_owner_val[powner->so_owner_len] = '\0'; if(pthread_mutex_init(&powner->so_mutex, NULL) == -1) { ReleaseToPool(powner, &pclient->pool_state_owner); ReleaseToPool(powner_name, &pclient->pool_nfs4_owner_name); return NULL; } if(!nfs4_owner_Set(powner_name, powner)) { ReleaseToPool(powner, &pclient->pool_state_owner); ReleaseToPool(powner_name, &pclient->pool_nfs4_owner_name); return NULL; } if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; DisplayOwner(powner, str); LogFullDebug(COMPONENT_STATE, "New Open Owner %s", str); } return powner; }