int nlm4_Test_Message(nfs_arg_t * parg /* IN */ , exportlist_t * pexport /* IN */ , fsal_op_context_t * pcontext /* IN */ , cache_inode_client_t * pclient /* INOUT */ , hash_table_t * ht /* INOUT */ , struct svc_req *preq /* IN */ , nfs_res_t * pres /* OUT */ ) { state_nlm_client_t * nlm_client; nlm4_testargs * arg = &parg->arg_nlm4_test; int rc = NFS_REQ_OK; LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm_Test_Message"); nlm_client = get_nlm_client(TRUE, arg->alock.caller_name); if(nlm_client == NULL) rc = NFS_REQ_DROP; else rc = nlm4_Test(parg, pexport, pcontext, pclient, ht, preq, pres); if(rc == NFS_REQ_OK) rc = nlm_send_async_res_nlm4test(nlm_client, nlm4_test_message_resp, pres); if(rc == NFS_REQ_DROP) { if(nlm_client != NULL) dec_nlm_client_ref(nlm_client); LogCrit(COMPONENT_NLM, "Could not send async response for nlm_Test_Message"); } return NFS_REQ_DROP; }
static void nlm4_unlock_message_resp(state_async_queue_t *arg) { state_nlm_async_data_t *nlm_arg = &arg->state_async_data.state_nlm_async_data; if (isFullDebug(COMPONENT_NLM)) { char buffer[1024] = "\0"; netobj_to_string(&nlm_arg->nlm_async_args.nlm_async_res. res_nlm4test.cookie, buffer, 1024); LogFullDebug(COMPONENT_NLM, "Calling nlm_send_async cookie=%s status=%s", buffer, lock_result_str(nlm_arg->nlm_async_args. nlm_async_res.res_nlm4.stat.stat)); } nlm_send_async(NLMPROC4_UNLOCK_RES, nlm_arg->nlm_async_host, &(nlm_arg->nlm_async_args.nlm_async_res), NULL); nlm4_Unlock_Free(&nlm_arg->nlm_async_args.nlm_async_res); dec_nsm_client_ref(nlm_arg->nlm_async_host->slc_nsm_client); dec_nlm_client_ref(nlm_arg->nlm_async_host); gsh_free(arg); }
void dec_nlm_owner_ref_locked(state_owner_t *powner) { bool_t remove = FALSE; char str[HASHTABLE_DISPLAY_STRLEN]; if(isFullDebug(COMPONENT_STATE)) display_nlm_owner(powner, str); if(powner->so_refcount > 1) { powner->so_refcount--; LogFullDebug(COMPONENT_STATE, "Decrement refcount for NLM Owner powner=%p {%s}, refcount = %d", powner, str, powner->so_refcount); } else remove = TRUE; V(powner->so_mutex); if(remove) { hash_buffer_t buffkey, old_key, old_value; buffkey.pdata = (caddr_t) powner; buffkey.len = sizeof(*powner); switch(HashTable_DelRef(ht_nlm_owner, &buffkey, &old_key, &old_value, Hash_del_nlm_owner_ref)) { case HASHTABLE_SUCCESS: LogFullDebug(COMPONENT_STATE, "Free NLM Owner powner=%p {%s}, refcount = %d", powner, str, powner->so_refcount); dec_nlm_client_ref(powner->so_owner.so_nlm_owner.so_client); Mem_Free(old_key.pdata); Mem_Free(old_value.pdata); break; case HASHTABLE_NOT_DELETED: /* ref count didn't end up at 0, don't free. */ LogDebug(COMPONENT_STATE, "HashTable_DelRef didn't reduce refcount to 0 for powner=%p {%s}, refcount = %d", powner, str, powner->so_refcount); break; default: /* some problem occurred */ LogDebug(COMPONENT_STATE, "HashTable_DelRef failed for powner=%p {%s}", powner, str); break; } } }
static void nlm4_test_message_resp(nlm_async_queue_t *arg) { if(isFullDebug(COMPONENT_NLM)) { char buffer[1024]; netobj_to_string(&arg->nlm_async_args.nlm_async_res.res_nlm4test.cookie, buffer, 1024); LogFullDebug(COMPONENT_NLM, "Calling nlm_send_async cookie=%s status=%s", buffer, lock_result_str(arg->nlm_async_args.nlm_async_res.res_nlm4test.test_stat.stat)); } nlm_send_async(NLMPROC4_TEST_RES, arg->nlm_async_host, &(arg->nlm_async_args.nlm_async_res), NULL); nlm4_Test_Free(&arg->nlm_async_args.nlm_async_res); dec_nlm_client_ref(arg->nlm_async_host); Mem_Free(arg); }
/** * @brief Unlock Message * * @param[in] args * @param[in] req * @param[out] res * */ int nlm4_Unlock_Message(nfs_arg_t *args, struct svc_req *req, nfs_res_t *res) { state_nlm_client_t *nlm_client = NULL; state_nsm_client_t *nsm_client; nlm4_unlockargs *arg = &args->arg_nlm4_unlock; int rc = NFS_REQ_OK; LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm_Unlock_Message"); nsm_client = get_nsm_client(CARE_NO_MONITOR, req->rq_xprt, arg->alock.caller_name); if (nsm_client != NULL) nlm_client = get_nlm_client(CARE_NO_MONITOR, req->rq_xprt, nsm_client, arg->alock.caller_name); if (nlm_client == NULL) rc = NFS_REQ_DROP; else rc = nlm4_Unlock(args, req, res); if (rc == NFS_REQ_OK) rc = nlm_send_async_res_nlm4(nlm_client, nlm4_unlock_message_resp, res); if (rc == NFS_REQ_DROP) { if (nsm_client != NULL) dec_nsm_client_ref(nsm_client); if (nlm_client != NULL) dec_nlm_client_ref(nlm_client); LogCrit(COMPONENT_NLM, "Could not send async response for nlm_Unlock_Message"); } return NFS_REQ_DROP; }
void remove_nlm_owner(cache_inode_client_t * pclient, state_owner_t * powner, const char * str) { hash_buffer_t buffkey, old_key, old_value; buffkey.pdata = (caddr_t) powner; buffkey.len = sizeof(*powner); switch(HashTable_DelRef(ht_nlm_owner, &buffkey, &old_key, &old_value, Hash_dec_state_owner_ref)) { case HASHTABLE_SUCCESS: LogFullDebug(COMPONENT_STATE, "Free %s size %llx", str, (unsigned long long) old_value.len); dec_nlm_client_ref(powner->so_owner.so_nlm_owner.so_client); if(isFullDebug(COMPONENT_MEMLEAKS)) { memset(old_key.pdata, 0, old_key.len); memset(old_value.pdata, 0, old_value.len); } Mem_Free(old_key.pdata); Mem_Free(old_value.pdata); break; case HASHTABLE_NOT_DELETED: /* ref count didn't end up at 0, don't free. */ LogDebug(COMPONENT_STATE, "HashTable_DelRef didn't reduce refcount to 0 for %s", str); break; default: /* some problem occurred */ LogDebug(COMPONENT_STATE, "HashTable_DelRef failed for %s", str); break; } }
void free_nlm_owner(state_owner_t *powner) { if(powner->so_owner.so_nlm_owner.so_client != NULL) dec_nlm_client_ref(powner->so_owner.so_nlm_owner.so_client); }
state_owner_t *get_nlm_owner(care_t care, state_nlm_client_t * pclient, netobj * oh, uint32_t svid) { state_owner_t * pkey, *powner; if(pclient == NULL || oh == NULL || oh->n_len > MAX_NETOBJ_SZ) return NULL; pkey = (state_owner_t *)Mem_Alloc(sizeof(*pkey)); if(pkey == NULL) return NULL; memset(pkey, 0, sizeof(*pkey)); pkey->so_type = STATE_LOCK_OWNER_NLM; pkey->so_refcount = 1; pkey->so_owner.so_nlm_owner.so_client = pclient; pkey->so_owner.so_nlm_owner.so_nlm_svid = svid; pkey->so_owner_len = oh->n_len; memcpy(pkey->so_owner_val, oh->n_bytes, oh->n_len); if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_owner(pkey, str); LogFullDebug(COMPONENT_STATE, "Find NLM Owner KEY {%s}", str); } /* If we found it, return it, if we don't care, return NULL */ if(nlm_owner_Get_Pointer(pkey, &powner) == 1 || care == CARE_NOT) { /* Discard the key we created and return the found NLM Owner */ Mem_Free(pkey); if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_owner(powner, str); LogFullDebug(COMPONENT_STATE, "Found {%s}", str); } return powner; } powner = (state_owner_t *)Mem_Alloc(sizeof(*pkey)); if(powner == NULL) { Mem_Free(pkey); return NULL; } /* Copy everything over */ *powner = *pkey; init_glist(&powner->so_lock_list); if(pthread_mutex_init(&powner->so_mutex, NULL) == -1) { /* Mutex initialization failed, free the key and created owner */ Mem_Free(pkey); Mem_Free(powner); return NULL; } if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_owner(powner, str); LogFullDebug(COMPONENT_STATE, "New {%s}", str); } /* Ref count the client as being used by this owner */ inc_nlm_client_ref(pclient); if(nlm_owner_Set(pkey, powner) == 1) { if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_owner(powner, str); LogFullDebug(COMPONENT_STATE, "Set NLM Owner {%s}", str); } return powner; } dec_nlm_client_ref(pclient); Mem_Free(pkey); Mem_Free(powner); return NULL; }
int nlm4_Unshare(nfs_arg_t *args, struct svc_req *req, nfs_res_t *res) { nlm4_shareargs *arg = &args->arg_nlm4_share; struct fsal_obj_handle *obj; state_status_t state_status = STATE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2] = "\0"; state_nsm_client_t *nsm_client; state_nlm_client_t *nlm_client; state_owner_t *nlm_owner; state_t *nlm_state; int rc; /* NLM doesn't have a BADHANDLE error, nor can rpc_execute deal with * responding to an NLM_*_MSG call, so we check here if the export is * NULL and if so, handle the response. */ if (op_ctx->ctx_export == NULL) { res->res_nlm4share.stat = NLM4_STALE_FH; LogInfo(COMPONENT_NLM, "INVALID HANDLE: NLM4_UNSHARE"); return NFS_REQ_OK; } res->res_nlm4share.sequence = 0; netobj_to_string(&arg->cookie, buffer, 1024); if (isDebug(COMPONENT_NLM)) { char str[LEN_FH_STR]; char oh[MAXNETOBJ_SZ * 2] = "\0"; sprint_fhandle3(str, (struct nfs_fh3 *)&arg->share.fh); netobj_to_string(&arg->share.oh, oh, 1024); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling NLM4_UNSHARE handle: %s, cookie=%s, reclaim=%s, owner=%s, access=%d, deny=%d", str, buffer, arg->reclaim ? "yes" : "no", oh, arg->share.access, arg->share.mode); } copy_netobj(&res->res_nlm4share.cookie, &arg->cookie); rc = nlm_process_share_parms(req, &arg->share, op_ctx->fsal_export, &obj, CARE_NOT, &nsm_client, &nlm_client, &nlm_owner, &nlm_state); if (rc >= 0) { /* Present the error back to the client */ res->res_nlm4share.stat = (nlm4_stats) rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: NLM4_UNSHARE %s", lock_result_str(res->res_nlm4share.stat)); return NFS_REQ_OK; } state_status = state_nlm_share(obj, arg->share.access, arg->share.mode, nlm_owner, nlm_state, false, true); if (state_status != STATE_SUCCESS) { res->res_nlm4share.stat = nlm_convert_state_error(state_status); } else { res->res_nlm4share.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner); obj->obj_ops->put_ref(obj); dec_nlm_state_ref(nlm_state); LogDebug(COMPONENT_NLM, "REQUEST RESULT: NLM4_UNSHARE %s", lock_result_str(res->res_nlm4share.stat)); return NFS_REQ_OK; }
state_status_t nlm_granted_callback(cache_entry_t * pentry, state_lock_entry_t * lock_entry, state_status_t * pstatus) { fsal_op_context_t fsal_context, *pcontext = &fsal_context; state_block_data_t * block_data = lock_entry->sle_block_data; state_nlm_block_data_t * nlm_block_data = &block_data->sbd_block_data.sbd_nlm_block_data; state_cookie_entry_t * cookie_entry = NULL; state_async_queue_t * arg; nlm4_testargs * inarg; state_nlm_owner_t * nlm_grant_owner = &lock_entry->sle_owner->so_owner.so_nlm_owner; state_nlm_client_t * nlm_grant_client = nlm_grant_owner->so_client; granted_cookie_t nlm_grant_cookie; state_status_t dummy_status; if(nlm_block_data_to_fsal_context(block_data, &fsal_context) != TRUE) { *pstatus = STATE_INCONSISTENT_ENTRY; return *pstatus; } arg = gsh_malloc(sizeof(*arg)); if(arg == NULL) { /* If we fail allocation the best is to delete the block entry * so that client can try again and get the lock. May be * by then we are able to allocate objects */ *pstatus = STATE_MALLOC_ERROR; return *pstatus; } memset(arg, 0, sizeof(*arg)); /* Get a cookie to use for this grant */ next_granted_cookie(&nlm_grant_cookie); /* Add a cookie to the blocked lock pending grant. * It will also request lock from FSAL. * Could return STATE_LOCK_BLOCKED because FSAL would have had to block. */ if(state_add_grant_cookie(pentry, pcontext, &nlm_grant_cookie, sizeof(nlm_grant_cookie), lock_entry, &cookie_entry, pstatus) != STATE_SUCCESS) { free_grant_arg(arg); return *pstatus; } /* Fill in the arguments for the NLMPROC4_GRANTED_MSG call */ inc_nlm_client_ref(nlm_grant_client); arg->state_async_func = nlm4_send_grant_msg; arg->state_async_data.state_nlm_async_data.nlm_async_host = nlm_grant_client; arg->state_async_data.state_nlm_async_data.nlm_async_key = cookie_entry; inarg = &arg->state_async_data.state_nlm_async_data.nlm_async_args.nlm_async_grant; if(!copy_netobj(&inarg->alock.fh, &nlm_block_data->sbd_nlm_fh)) goto grant_fail_malloc; if(!fill_netobj(&inarg->alock.oh, lock_entry->sle_owner->so_owner_val, lock_entry->sle_owner->so_owner_len)) goto grant_fail_malloc; if(!fill_netobj(&inarg->cookie, (char *) &nlm_grant_cookie, sizeof(nlm_grant_cookie))) goto grant_fail_malloc; inarg->alock.caller_name = gsh_strdup(nlm_grant_client->slc_nlm_caller_name); if(!inarg->alock.caller_name) goto grant_fail_malloc; inarg->exclusive = lock_entry->sle_lock.lock_type == FSAL_LOCK_W; inarg->alock.svid = nlm_grant_owner->so_nlm_svid; inarg->alock.l_offset = lock_entry->sle_lock.lock_start; inarg->alock.l_len = lock_entry->sle_lock.lock_length; if(isDebug(COMPONENT_NLM)) { char buffer[1024]; netobj_to_string(&inarg->cookie, buffer, sizeof(buffer)); LogDebug(COMPONENT_NLM, "Sending GRANTED for arg=%p svid=%d start=%llx len=%llx cookie=%s", arg, inarg->alock.svid, (unsigned long long) inarg->alock.l_offset, (unsigned long long) inarg->alock.l_len, buffer); } /* Now try to schedule NLMPROC4_GRANTED_MSG call */ *pstatus = state_async_schedule(arg); if(*pstatus != STATE_SUCCESS) goto grant_fail; return *pstatus; grant_fail_malloc: *pstatus = STATE_MALLOC_ERROR; grant_fail: /* Something went wrong after we added a grant cookie, need to clean up */ dec_nlm_client_ref(nlm_grant_client); /* Clean up NLMPROC4_GRANTED_MSG arguments */ free_grant_arg(arg); /* Cancel the pending grant to release the cookie */ if(state_cancel_grant(pcontext, cookie_entry, &dummy_status) != STATE_SUCCESS) { /* Not much we can do other than log that something bad happened. */ LogCrit(COMPONENT_NLM, "Unable to clean up GRANTED lock after error"); } return *pstatus; }
int nlm_process_parameters(struct svc_req * preq, bool_t exclusive, nlm4_lock * alock, fsal_lock_param_t * plock, cache_entry_t ** ppentry, fsal_op_context_t * pcontext, care_t care, state_nsm_client_t ** ppnsm_client, state_nlm_client_t ** ppnlm_client, state_owner_t ** ppowner, state_block_data_t ** ppblock_data) { cache_inode_fsal_data_t fsal_data; fsal_attrib_list_t attr; cache_inode_status_t cache_status; SVCXPRT *ptr_svc = preq->rq_xprt; int rc; *ppnsm_client = NULL; *ppnlm_client = NULL; *ppowner = NULL; /* Convert file handle into a cache entry */ if(alock->fh.n_len > MAX_NETOBJ_SZ || !nfs3_FhandleToFSAL((nfs_fh3 *) &alock->fh, &fsal_data.fh_desc, pcontext)) { /* handle is not valid */ return NLM4_STALE_FH; } /* Now get the cached inode attributes */ *ppentry = cache_inode_get(&fsal_data, &attr, pcontext, NULL, &cache_status); if(*ppentry == NULL) { /* handle is not valid */ return NLM4_STALE_FH; } *ppnsm_client = get_nsm_client(care, ptr_svc, alock->caller_name); if(*ppnsm_client == NULL) { /* If NSM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, alock->caller_name); if(*ppnlm_client == NULL) { /* If NLM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ dec_nsm_client_ref(*ppnsm_client); if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppowner = get_nlm_owner(care, *ppnlm_client, &alock->oh, alock->svid); if(*ppowner == NULL) { LogDebug(COMPONENT_NLM, "Could not get NLM Owner"); dec_nsm_client_ref(*ppnsm_client); dec_nlm_client_ref(*ppnlm_client); *ppnlm_client = NULL; /* If owner is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } if(ppblock_data != NULL) { *ppblock_data = gsh_calloc(1, sizeof(**ppblock_data)); /* Fill in the block data, if we don't get one, we will just proceed * without (which will mean the lock doesn't block. */ if(*ppblock_data != NULL) { if(copy_xprt_addr(&(*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_hostaddr, ptr_svc) == 0) { LogFullDebug(COMPONENT_NLM, "copy_xprt_addr failed for Program %d, Version %d, Function %d", (int)preq->rq_prog, (int)preq->rq_vers, (int)preq->rq_proc); gsh_free(*ppblock_data); *ppblock_data = NULL; rc = NLM4_FAILED; goto out_put; } (*ppblock_data)->sbd_granted_callback = nlm_granted_callback; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_bytes = (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_len = alock->fh.n_len; memcpy((*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf, alock->fh.n_bytes, alock->fh.n_len); /* FSF TODO: Ultimately I think the following will go away, we won't need the context, just the export */ /* Copy credentials from pcontext */ #ifdef _USE_HPSS /** @todo : PhD: Think about removing hpsscred_t from FSAL */ (*ppblock_data)->sbd_credential.user = pcontext->credential.hpss_usercred.Uid ; (*ppblock_data)->sbd_credential.group = pcontext->credential.hpss_usercred.Gid ; #else (*ppblock_data)->sbd_credential = pcontext->credential; /* Copy the alt groups list */ if(pcontext->credential.nbgroups != 0) { (*ppblock_data)->sbd_credential.alt_groups = gsh_malloc(sizeof(gid_t) * pcontext->credential.nbgroups); if((*ppblock_data)->sbd_credential.alt_groups == NULL) { gsh_free(*ppblock_data); *ppblock_data = NULL; rc = NLM4_FAILED; goto out_put; } memcpy((*ppblock_data)->sbd_credential.alt_groups, pcontext->credential.alt_groups, pcontext->credential.nbgroups); } #endif } } /* Fill in plock */ plock->lock_type = exclusive ? FSAL_LOCK_W : FSAL_LOCK_R; plock->lock_start = alock->l_offset; plock->lock_length = alock->l_len; LogFullDebug(COMPONENT_NLM, "Parameters Processed"); return -1; out_put: cache_inode_put(*ppentry); *ppentry = NULL; return rc; }
int nlm_process_parameters(struct svc_req * preq, bool_t exclusive, nlm4_lock * alock, state_lock_desc_t * plock, hash_table_t * ht, cache_entry_t ** ppentry, fsal_op_context_t * pcontext, cache_inode_client_t * pclient, care_t care, state_nsm_client_t ** ppnsm_client, state_nlm_client_t ** ppnlm_client, state_owner_t ** ppowner, state_block_data_t ** ppblock_data) { cache_inode_fsal_data_t fsal_data; fsal_attrib_list_t attr; cache_inode_status_t cache_status; SVCXPRT *ptr_svc = preq->rq_xprt; *ppnsm_client = NULL; *ppnlm_client = NULL; *ppowner = NULL; /* Convert file handle into a cache entry */ if(alock->fh.n_len > MAX_NETOBJ_SZ || !nfs3_FhandleToFSAL((nfs_fh3 *) &alock->fh, &fsal_data.handle, pcontext)) { /* handle is not valid */ return NLM4_STALE_FH; } /* Now get the cached inode attributes */ fsal_data.cookie = DIR_START; *ppentry = cache_inode_get(&fsal_data, CACHE_INODE_JOKER_POLICY, &attr, ht, pclient, pcontext, &cache_status); if(*ppentry == NULL) { /* handle is not valid */ return NLM4_STALE_FH; } *ppnsm_client = get_nsm_client(care, ptr_svc, alock->caller_name); if(*ppnsm_client == NULL) { /* If NSM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) return NLM4_DENIED_NOLOCKS; else return NLM4_GRANTED; } *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, alock->caller_name); if(*ppnlm_client == NULL) { /* If NLM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ dec_nsm_client_ref(*ppnsm_client); if(care != CARE_NOT) return NLM4_DENIED_NOLOCKS; else return NLM4_GRANTED; } *ppowner = get_nlm_owner(care, *ppnlm_client, &alock->oh, alock->svid); if(*ppowner == NULL) { LogDebug(COMPONENT_NLM, "Could not get NLM Owner"); dec_nsm_client_ref(*ppnsm_client); dec_nlm_client_ref(*ppnlm_client); *ppnlm_client = NULL; /* If owner is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care) return NLM4_DENIED_NOLOCKS; else return NLM4_GRANTED; } if(ppblock_data != NULL) { *ppblock_data = (state_block_data_t *) Mem_Alloc_Label(sizeof(**ppblock_data), "NLM_Block_Data"); /* Fill in the block data, if we don't get one, we will just proceed * without (which will mean the lock doesn't block. */ if(*ppblock_data != NULL) { memset(*ppblock_data, 0, sizeof(**ppblock_data)); if(copy_xprt_addr(&(*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_hostaddr, ptr_svc) == 0) { LogFullDebug(COMPONENT_NLM, "copy_xprt_addr failed for Program %d, Version %d, Function %d", (int)preq->rq_prog, (int)preq->rq_vers, (int)preq->rq_proc); Mem_Free(*ppblock_data); *ppblock_data = NULL; return NLM4_FAILED; } (*ppblock_data)->sbd_granted_callback = nlm_granted_callback; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_bytes = (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_len = alock->fh.n_len; memcpy((*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf, alock->fh.n_bytes, alock->fh.n_len); /* FSF TODO: Ultimately I think the following will go away, we won't need the context, just the export */ /* Copy credentials from pcontext */ (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_credential = pcontext->credential; } } /* Fill in plock */ plock->sld_type = exclusive ? STATE_LOCK_W : STATE_LOCK_R; plock->sld_offset = alock->l_offset; plock->sld_length = alock->l_len; LogFullDebug(COMPONENT_NLM, "Parameters Processed"); return -1; }
int nlm4_Test(nfs_arg_t * parg /* IN */ , exportlist_t * pexport /* IN */ , fsal_op_context_t * pcontext /* IN */ , cache_inode_client_t * pclient /* INOUT */ , hash_table_t * ht /* INOUT */ , struct svc_req *preq /* IN */ , nfs_res_t * pres /* OUT */ ) { nlm4_testargs * arg = &parg->arg_nlm4_test; cache_entry_t * pentry; state_status_t state_status = CACHE_INODE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2]; state_nlm_client_t * nlm_client; state_owner_t * nlm_owner, * holder; state_lock_desc_t lock, conflict; int rc; netobj_to_string(&arg->cookie, buffer, 1024); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Test svid=%d off=%llx len=%llx cookie=%s", (int) arg->alock.svid, (unsigned long long) arg->alock.l_offset, (unsigned long long) arg->alock.l_len, buffer); if(!copy_netobj(&pres->res_nlm4test.cookie, &arg->cookie)) { pres->res_nlm4test.test_stat.stat = NLM4_FAILED; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Test %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } if(in_nlm_grace_period()) { pres->res_nlm4test.test_stat.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Test %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } /* TODO FSF: * * TEST passes TRUE for care because we do need a non-NULL owner, but * we could expand the options to allow for a "free" owner to be * returned, that doesn't need to be in the hash table, so if the * owner isn't found in the Hash table, don't add it, just return * the "free" owner. */ rc = nlm_process_parameters(preq, arg->exclusive, &arg->alock, &lock, ht, &pentry, pcontext, pclient, CARE_NO_MONITOR, &nlm_client, &nlm_owner, NULL); if(rc >= 0) { /* Present the error back to the client */ pres->res_nlm4.stat.stat = (nlm4_stats)rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } if(state_test(pentry, pcontext, nlm_owner, &lock, &holder, &conflict, pclient, &state_status) != STATE_SUCCESS) { pres->res_nlm4test.test_stat.stat = nlm_convert_state_error(state_status); if(state_status == STATE_LOCK_CONFLICT) { nlm_process_conflict(&pres->res_nlm4test.test_stat.nlm4_testrply_u.holder, holder, &conflict); } } else { pres->res_nlm4.stat.stat = NLM4_GRANTED; } LogFullDebug(COMPONENT_NLM, "Back from state_test"); /* Release the NLM Client and NLM Owner references we have */ dec_nlm_client_ref(nlm_client); dec_nlm_owner_ref(nlm_owner); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Test %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; }
/** * * nlm4_send_grant_msg: Send NLMPROC4_GRANTED_MSG * * This runs in the nlm_asyn_thread context. */ static void nlm4_send_grant_msg(state_async_queue_t *arg) { int retval; char buffer[1024]; state_status_t state_status = STATE_SUCCESS; state_cookie_entry_t *cookie_entry; state_nlm_async_data_t *nlm_arg = &arg->state_async_data.state_nlm_async_data; struct root_op_context root_op_context; struct gsh_export *export; if (isDebug(COMPONENT_NLM)) { netobj_to_string(&nlm_arg->nlm_async_args.nlm_async_grant. cookie, buffer, sizeof(buffer)); LogDebug(COMPONENT_NLM, "Sending GRANTED for arg=%p svid=%d start=%llx len=%llx cookie=%s", arg, nlm_arg->nlm_async_args.nlm_async_grant.alock.svid, (unsigned long long)nlm_arg->nlm_async_args. nlm_async_grant.alock.l_offset, (unsigned long long)nlm_arg->nlm_async_args. nlm_async_grant.alock.l_len, buffer); } retval = nlm_send_async(NLMPROC4_GRANTED_MSG, nlm_arg->nlm_async_host, &nlm_arg->nlm_async_args.nlm_async_grant, nlm_arg->nlm_async_key); dec_nlm_client_ref(nlm_arg->nlm_async_host); /* If success, we are done. */ if (retval == RPC_SUCCESS) goto out; /* * We are not able call granted callback. Some client may retry * the lock again. So remove the existing blocked nlm entry */ LogMajor(COMPONENT_NLM, "GRANTED_MSG RPC call failed with return code %d. Removing the blocking lock", retval); state_status = state_find_grant( nlm_arg->nlm_async_args.nlm_async_grant.cookie.n_bytes, nlm_arg->nlm_async_args.nlm_async_grant.cookie.n_len, &cookie_entry); if (state_status != STATE_SUCCESS) { /* This must be an old NLM_GRANTED_RES */ LogFullDebug(COMPONENT_NLM, "Could not find cookie=%s status=%s", buffer, state_err_str(state_status)); goto out; } if (cookie_entry->sce_lock_entry->sle_block_data == NULL) { /* Wow, we're not doing well... */ LogFullDebug(COMPONENT_NLM, "Could not find block data for cookie=%s (must be an old NLM_GRANTED_RES)", buffer); goto out; } /* Initialize a context, it is ok if the export is stale because * we must clean up the cookie_entry. */ export = cookie_entry->sce_lock_entry->sle_export;
int nlm4_Unlock(nfs_arg_t *args, struct svc_req *req, nfs_res_t *res) { nlm4_unlockargs *arg = &args->arg_nlm4_unlock; struct fsal_obj_handle *obj; state_status_t state_status = STATE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2] = "\0"; state_nsm_client_t *nsm_client; state_nlm_client_t *nlm_client; state_owner_t *nlm_owner; fsal_lock_param_t lock; int rc; state_t *state; /* NLM doesn't have a BADHANDLE error, nor can rpc_execute deal with * responding to an NLM_*_MSG call, so we check here if the export is * NULL and if so, handle the response. */ if (op_ctx->ctx_export == NULL) { res->res_nlm4.stat.stat = NLM4_STALE_FH; LogInfo(COMPONENT_NLM, "INVALID HANDLE: nlm4_Unlock"); return NFS_REQ_OK; } netobj_to_string(&arg->cookie, buffer, sizeof(buffer)); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Unlock svid=%d off=%llx len=%llx cookie=%s", (int)arg->alock.svid, (unsigned long long)arg->alock.l_offset, (unsigned long long)arg->alock.l_len, buffer); copy_netobj(&res->res_nlm4test.cookie, &arg->cookie); if (nfs_in_grace()) { res->res_nlm4.stat.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(res->res_nlm4.stat.stat)); return NFS_REQ_OK; } /* unlock doesn't care if owner is found */ rc = nlm_process_parameters(req, false, &arg->alock, &lock, &obj, CARE_NOT, &nsm_client, &nlm_client, &nlm_owner, NULL, 0, &state); if (rc >= 0) { /* resent the error back to the client */ res->res_nlm4.stat.stat = (nlm4_stats) rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(res->res_nlm4.stat.stat)); return NFS_REQ_OK; } if (state != NULL) state_status = state_unlock(obj, state, nlm_owner, false, 0, &lock); if (state_status != STATE_SUCCESS) { /* Unlock could fail in the FSAL and make a bit of a mess, * especially if we are in out of memory situation. Such an * error is logged by Cache Inode. */ res->res_nlm4test.test_stat.stat = nlm_convert_state_error(state_status); } else { res->res_nlm4.stat.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ if (state != NULL) dec_state_t_ref(state); dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner); obj->obj_ops.put_ref(obj); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(res->res_nlm4.stat.stat)); return NFS_REQ_OK; }
state_nlm_client_t *get_nlm_client(care_t care, SVCXPRT * xprt, state_nsm_client_t * pnsm_client, char * caller_name) { state_nlm_client_t key; state_nlm_client_t * pclient; char str[HASHTABLE_DISPLAY_STRLEN]; struct hash_latch latch; hash_error_t rc; hash_buffer_t buffkey; hash_buffer_t buffval; if(caller_name == NULL) return NULL; memset(&key, 0, sizeof(key)); key.slc_nsm_client = pnsm_client; key.slc_nlm_caller_name_len = strlen(caller_name); key.slc_client_type = svc_get_xprt_type(xprt); if(key.slc_nlm_caller_name_len > LM_MAXSTRLEN) return NULL; key.slc_nlm_caller_name = caller_name; if(isFullDebug(COMPONENT_STATE)) { display_nlm_client(&key, str); LogFullDebug(COMPONENT_STATE, "Find {%s}", str); } buffkey.pdata = &key; buffkey.len = sizeof(key); rc = HashTable_GetLatch(ht_nlm_client, &buffkey, &buffval, TRUE, &latch); /* If we found it, return it */ if(rc == HASHTABLE_SUCCESS) { pclient = buffval.pdata; /* Return the found NLM Client */ if(isFullDebug(COMPONENT_STATE)) { display_nlm_client(pclient, str); LogFullDebug(COMPONENT_STATE, "Found {%s}", str); } /* Increment refcount under hash latch. * This prevents dec ref from removing this entry from hash if a race * occurs. */ inc_nlm_client_ref(pclient); HashTable_ReleaseLatched(ht_nlm_client, &latch); if(care == CARE_MONITOR && !nsm_monitor(pnsm_client)) { dec_nlm_client_ref(pclient); pclient = NULL; } return pclient; } /* An error occurred, return NULL */ if(rc != HASHTABLE_ERROR_NO_SUCH_KEY) { display_nlm_client(&key, str); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return NULL; } /* Not found, but we don't care, return NULL */ if(care == CARE_NOT) { /* Return the found NLM Client */ if(isFullDebug(COMPONENT_STATE)) { display_nlm_client(&key, str); LogFullDebug(COMPONENT_STATE, "Ignoring {%s}", str); } HashTable_ReleaseLatched(ht_nlm_client, &latch); return NULL; } pclient = gsh_malloc(sizeof(*pclient)); if(pclient == NULL) { display_nlm_client(&key, str); LogCrit(COMPONENT_STATE, "No memory for {%s}", str); return NULL; } /* Copy everything over */ memcpy(pclient, &key, sizeof(key)); pclient->slc_nlm_caller_name = gsh_strdup(key.slc_nlm_caller_name); /* Take a reference to the NSM Client */ inc_nsm_client_ref(pnsm_client); if(pclient->slc_nlm_caller_name == NULL) { /* Discard the created client */ free_nlm_client(pclient); return NULL; } pclient->slc_refcount = 1; if(isFullDebug(COMPONENT_STATE)) { display_nlm_client(pclient, str); LogFullDebug(COMPONENT_STATE, "New {%s}", str); } buffkey.pdata = pclient; buffkey.len = sizeof(*pclient); buffval.pdata = pclient; buffval.len = sizeof(*pclient); rc = HashTable_SetLatched(ht_nlm_client, &buffval, &buffval, &latch, FALSE, NULL, NULL); /* An error occurred, return NULL */ if(rc != HASHTABLE_SUCCESS) { display_nlm_client(pclient, str); LogCrit(COMPONENT_STATE, "Error %s, inserting {%s}", hash_table_err_to_str(rc), str); free_nlm_client(pclient); return NULL; } if(care != CARE_MONITOR || nsm_monitor(pnsm_client)) return pclient; /* Failed to monitor, release client reference * and almost certainly remove it from the hash table. */ dec_nlm_client_ref(pclient); return NULL; }
int nlm4_Share(nfs_arg_t * parg, exportlist_t * pexport, fsal_op_context_t * pcontext, nfs_worker_data_t * pworker, struct svc_req * preq, nfs_res_t * pres) { nlm4_shareargs * arg = &parg->arg_nlm4_share; cache_entry_t * pentry; state_status_t state_status = STATE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2]; state_nsm_client_t * nsm_client; state_nlm_client_t * nlm_client; state_owner_t * nlm_owner; int rc; int grace = nfs_in_grace(); pres->res_nlm4share.sequence = 0; netobj_to_string(&arg->cookie, buffer, 1024); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Share cookie=%s reclaim=%s", buffer, arg->reclaim ? "yes" : "no"); if(!copy_netobj(&pres->res_nlm4share.cookie, &arg->cookie)) { pres->res_nlm4share.stat = NLM4_FAILED; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; } /* Allow only reclaim share request during recovery and visa versa. * Note: NLM_SHARE is indicated to be non-monitored, however, it does * have a reclaim flag, so we will honor the reclaim flag if used. */ if((grace && !arg->reclaim) || (!grace && arg->reclaim)) { pres->res_nlm4share.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; } rc = nlm_process_share_parms(preq, &arg->share, &pentry, pcontext, CARE_NO_MONITOR, &nsm_client, &nlm_client, &nlm_owner); if(rc >= 0) { /* Present the error back to the client */ pres->res_nlm4share.stat = (nlm4_stats)rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; } if(state_nlm_share(pentry, pcontext, pexport, arg->share.access, arg->share.mode, nlm_owner, &state_status) != STATE_SUCCESS) { pres->res_nlm4share.stat = nlm_convert_state_error(state_status); } else { pres->res_nlm4share.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner); cache_inode_put(pentry); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(pres->res_nlm4share.stat)); return NFS_REQ_OK; }
int nlm4_Lock(nfs_arg_t * parg /* IN */ , exportlist_t * pexport /* IN */ , fsal_op_context_t * pcontext /* IN */ , cache_inode_client_t * pclient /* INOUT */ , hash_table_t * ht /* INOUT */ , struct svc_req * preq /* IN */ , nfs_res_t * pres /* OUT */ ) { nlm4_lockargs * arg = &parg->arg_nlm4_lock; cache_entry_t * pentry; state_status_t state_status = CACHE_INODE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2]; state_nsm_client_t * nsm_client; state_nlm_client_t * nlm_client; state_owner_t * nlm_owner, * holder; state_lock_desc_t lock, conflict; int rc; state_block_data_t * pblock_data; netobj_to_string(&arg->cookie, buffer, 1024); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Lock svid=%d off=%llx len=%llx cookie=%s", (int) arg->alock.svid, (unsigned long long) arg->alock.l_offset, (unsigned long long) arg->alock.l_len, buffer); if(!copy_netobj(&pres->res_nlm4test.cookie, &arg->cookie)) { pres->res_nlm4.stat.stat = NLM4_FAILED; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Test %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } /* allow only reclaim lock request during recovery */ if(in_nlm_grace_period() && !arg->reclaim) { pres->res_nlm4.stat.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Lock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } if(!in_nlm_grace_period() && arg->reclaim) { pres->res_nlm4.stat.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Lock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } rc = nlm_process_parameters(preq, arg->exclusive, &arg->alock, &lock, ht, &pentry, pcontext, pclient, CARE_MONITOR, &nsm_client, &nlm_client, &nlm_owner, &pblock_data); if(rc >= 0) { /* Present the error back to the client */ pres->res_nlm4.stat.stat = (nlm4_stats)rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } /* Cast the state number into a state pointer to protect * locks from a client that has rebooted from the SM_NOTIFY * that will release old locks */ if(state_lock(pentry, pcontext, nlm_owner, (void *) (ptrdiff_t) arg->state, arg->block, pblock_data, &lock, &holder, &conflict, pclient, &state_status) != STATE_SUCCESS) { pres->res_nlm4test.test_stat.stat = nlm_convert_state_error(state_status); if(state_status == STATE_LOCK_CONFLICT) { nlm_process_conflict(&pres->res_nlm4test.test_stat.nlm4_testrply_u.holder, holder, &conflict, pclient); } /* If we didn't block, release the block data */ if(state_status != STATE_LOCK_BLOCKED && pblock_data != NULL) Mem_Free(pblock_data); } else { pres->res_nlm4.stat.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner, pclient); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Lock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; }
/** * * nlm4_send_grant_msg: Send NLMPROC4_GRANTED_MSG * * This runs in the nlm_asyn_thread context. */ static void nlm4_send_grant_msg(state_async_queue_t *arg) { int retval; char buffer[1024]; state_status_t state_status = STATE_SUCCESS; state_cookie_entry_t * cookie_entry; fsal_op_context_t context, * pcontext = &context; state_nlm_async_data_t * nlm_arg = &arg->state_async_data.state_nlm_async_data; if(isDebug(COMPONENT_NLM)) { netobj_to_string(&nlm_arg->nlm_async_args.nlm_async_grant.cookie, buffer, sizeof(buffer)); LogDebug(COMPONENT_NLM, "Sending GRANTED for arg=%p svid=%d start=%llx len=%llx cookie=%s", arg, nlm_arg->nlm_async_args.nlm_async_grant.alock.svid, (unsigned long long) nlm_arg->nlm_async_args.nlm_async_grant.alock.l_offset, (unsigned long long) nlm_arg->nlm_async_args.nlm_async_grant.alock.l_len, buffer); } retval = nlm_send_async(NLMPROC4_GRANTED_MSG, nlm_arg->nlm_async_host, &(nlm_arg->nlm_async_args.nlm_async_grant), nlm_arg->nlm_async_key); dec_nlm_client_ref(nlm_arg->nlm_async_host); free_grant_arg(arg); /* If success, we are done. */ if(retval == RPC_SUCCESS) return; /* * We are not able call granted callback. Some client may retry * the lock again. So remove the existing blocked nlm entry */ LogMajor(COMPONENT_NLM, "GRANTED_MSG RPC call failed with return code %d. Removing the blocking lock", retval); if(state_find_grant(nlm_arg->nlm_async_args.nlm_async_grant.cookie.n_bytes, nlm_arg->nlm_async_args.nlm_async_grant.cookie.n_len, &cookie_entry, &state_status) != STATE_SUCCESS) { /* This must be an old NLM_GRANTED_RES */ LogFullDebug(COMPONENT_NLM, "Could not find cookie=%s status=%s", buffer, state_err_str(state_status)); return; } PTHREAD_RWLOCK_WRLOCK(&cookie_entry->sce_pentry->state_lock); if(cookie_entry->sce_lock_entry->sle_block_data == NULL || !nlm_block_data_to_fsal_context(cookie_entry->sce_lock_entry->sle_block_data, pcontext)) { /* Wow, we're not doing well... */ PTHREAD_RWLOCK_UNLOCK(&cookie_entry->sce_pentry->state_lock); LogFullDebug(COMPONENT_NLM, "Could not find block data for cookie=%s (must be an old NLM_GRANTED_RES)", buffer); return; } PTHREAD_RWLOCK_UNLOCK(&cookie_entry->sce_pentry->state_lock); if(state_release_grant(pcontext, cookie_entry, &state_status) != STATE_SUCCESS) { /* Huh? */ LogFullDebug(COMPONENT_NLM, "Could not release cookie=%s status=%s", buffer, state_err_str(state_status)); } }
/** * @brief Get an NLM client * * @param[in] care Care status * @param[in] xprt RPC transport * @param[in] nsm_client Related NSM client * @param[in] caller_name Caller name * * @return NLM client or NULL. */ state_nlm_client_t *get_nlm_client(care_t care, SVCXPRT *xprt, state_nsm_client_t *nsm_client, char *caller_name) { state_nlm_client_t key; state_nlm_client_t *pclient; char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; struct hash_latch latch; hash_error_t rc; struct gsh_buffdesc buffkey; struct gsh_buffdesc buffval; struct sockaddr_storage local_addr; socklen_t addr_len; if (caller_name == NULL) return NULL; memset(&key, 0, sizeof(key)); key.slc_nsm_client = nsm_client; key.slc_nlm_caller_name_len = strlen(caller_name); key.slc_client_type = svc_get_xprt_type(xprt); addr_len = sizeof(local_addr); if (getsockname(xprt->xp_fd, (struct sockaddr *)&local_addr, &addr_len) == -1) { LogEvent(COMPONENT_CLIENTID, "Failed to get local addr."); } else { memcpy(&(key.slc_server_addr), &local_addr, sizeof(struct sockaddr_storage)); } if (key.slc_nlm_caller_name_len > LM_MAXSTRLEN) return NULL; key.slc_nlm_caller_name = caller_name; if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, &key); LogFullDebug(COMPONENT_STATE, "Find {%s}", str); } buffkey.addr = &key; buffkey.len = sizeof(key); rc = hashtable_getlatch(ht_nlm_client, &buffkey, &buffval, true, &latch); /* If we found it, return it */ if (rc == HASHTABLE_SUCCESS) { pclient = buffval.addr; /* Return the found NLM Client */ if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, pclient); LogFullDebug(COMPONENT_STATE, "Found {%s}", str); } /* Increment refcount under hash latch. * This prevents dec ref from removing this entry from hash * if a race occurs. */ inc_nlm_client_ref(pclient); hashtable_releaselatched(ht_nlm_client, &latch); if (care == CARE_MONITOR && !nsm_monitor(nsm_client)) { dec_nlm_client_ref(pclient); pclient = NULL; } return pclient; } /* An error occurred, return NULL */ if (rc != HASHTABLE_ERROR_NO_SUCH_KEY) { display_nlm_client(&dspbuf, &key); LogCrit(COMPONENT_STATE, "Error %s, could not find {%s}", hash_table_err_to_str(rc), str); return NULL; } /* Not found, but we don't care, return NULL */ if (care == CARE_NOT) { /* Return the found NLM Client */ if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, &key); LogFullDebug(COMPONENT_STATE, "Ignoring {%s}", str); } hashtable_releaselatched(ht_nlm_client, &latch); return NULL; } pclient = gsh_malloc(sizeof(*pclient)); if (pclient == NULL) { display_nlm_client(&dspbuf, &key); LogCrit(COMPONENT_STATE, "No memory for {%s}", str); return NULL; } /* Copy everything over */ memcpy(pclient, &key, sizeof(key)); pclient->slc_nlm_caller_name = gsh_strdup(key.slc_nlm_caller_name); /* Take a reference to the NSM Client */ inc_nsm_client_ref(nsm_client); if (pclient->slc_nlm_caller_name == NULL) { /* Discard the created client */ free_nlm_client(pclient); return NULL; } pclient->slc_refcount = 1; if (isFullDebug(COMPONENT_STATE)) { display_nlm_client(&dspbuf, pclient); LogFullDebug(COMPONENT_STATE, "New {%s}", str); } buffkey.addr = pclient; buffkey.len = sizeof(*pclient); buffval.addr = pclient; buffval.len = sizeof(*pclient); rc = hashtable_setlatched(ht_nlm_client, &buffval, &buffval, &latch, false, NULL, NULL); /* An error occurred, return NULL */ if (rc != HASHTABLE_SUCCESS) { display_nlm_client(&dspbuf, pclient); LogCrit(COMPONENT_STATE, "Error %s, inserting {%s}", hash_table_err_to_str(rc), str); free_nlm_client(pclient); return NULL; } if (care != CARE_MONITOR || nsm_monitor(nsm_client)) return pclient; /* Failed to monitor, release client reference * and almost certainly remove it from the hash table. */ dec_nlm_client_ref(pclient); return NULL; }
int nlm_process_share_parms(struct svc_req * preq, nlm4_share * share, cache_entry_t ** ppentry, fsal_op_context_t * pcontext, care_t care, state_nsm_client_t ** ppnsm_client, state_nlm_client_t ** ppnlm_client, state_owner_t ** ppowner) { cache_inode_fsal_data_t fsal_data; fsal_attrib_list_t attr; cache_inode_status_t cache_status; SVCXPRT *ptr_svc = preq->rq_xprt; int rc; *ppnsm_client = NULL; *ppnlm_client = NULL; *ppowner = NULL; /* Convert file handle into a cache entry */ if(share->fh.n_len > MAX_NETOBJ_SZ || !nfs3_FhandleToFSAL((nfs_fh3 *) &share->fh, &fsal_data.fh_desc, pcontext)) { /* handle is not valid */ return NLM4_STALE_FH; } /* Now get the cached inode attributes */ *ppentry = cache_inode_get(&fsal_data, &attr, pcontext, NULL, &cache_status); if(*ppentry == NULL) { /* handle is not valid */ return NLM4_STALE_FH; } *ppnsm_client = get_nsm_client(care, ptr_svc, share->caller_name); if(*ppnsm_client == NULL) { /* If NSM Client is not found, and we don't care (for unshare), * just return GRANTED (the unshare must succeed, there can't be * any shares). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, share->caller_name); if(*ppnlm_client == NULL) { /* If NLM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ dec_nsm_client_ref(*ppnsm_client); if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } *ppowner = get_nlm_owner(care, *ppnlm_client, &share->oh, 0); if(*ppowner == NULL) { LogDebug(COMPONENT_NLM, "Could not get NLM Owner"); dec_nsm_client_ref(*ppnsm_client); dec_nlm_client_ref(*ppnlm_client); *ppnlm_client = NULL; /* If owner is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) rc = NLM4_DENIED_NOLOCKS; else rc = NLM4_GRANTED; goto out_put; } LogFullDebug(COMPONENT_NLM, "Parameters Processed"); return -1; out_put: cache_inode_put(*ppentry); *ppentry = NULL; return rc; }
state_nlm_client_t *get_nlm_client(care_t care, SVCXPRT * xprt, state_nsm_client_t * pnsm_client, const char * caller_name) { state_nlm_client_t *pkey, *pclient; if(caller_name == NULL) return NULL; pkey = (state_nlm_client_t *)Mem_Alloc(sizeof(*pkey)); if(pkey == NULL) return NULL; memset(pkey, 0, sizeof(*pkey)); pkey->slc_refcount = 1; pkey->slc_nsm_client = pnsm_client; pkey->slc_nlm_caller_name_len = strlen(caller_name); pkey->slc_client_type = get_xprt_type(xprt); if(pkey->slc_nlm_caller_name_len > LM_MAXSTRLEN) { /* Discard the key we created */ Mem_Free(pkey); return NULL; } memcpy(pkey->slc_nlm_caller_name, caller_name, pkey->slc_nlm_caller_name_len); pkey->slc_nlm_caller_name[pkey->slc_nlm_caller_name_len] = '\0'; if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_client(pkey, str); LogFullDebug(COMPONENT_STATE, "Find NLM Client pkey {%s}", str); } /* If we found it, return it, if we don't care, return NULL */ if(nlm_client_Get_Pointer(pkey, &pclient) == 1 || care == CARE_NOT) { /* Discard the key we created and return the found NLM Client */ Mem_Free(pkey); if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_client(pclient, str); LogFullDebug(COMPONENT_STATE, "Found NLM Client {%s}", str); } if(care == CARE_MONITOR) if(!nsm_monitor(pnsm_client)) { dec_nlm_client_ref(pclient); return NULL; } return pclient; } pclient = (state_nlm_client_t *)Mem_Alloc(sizeof(*pkey)); if(pclient == NULL) { Mem_Free(pkey); return NULL; } /* Copy everything over */ *pclient = *pkey; if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_client(pclient, str); LogFullDebug(COMPONENT_STATE, "New NLM Client {%s}", str); } if(pthread_mutex_init(&pclient->slc_mutex, NULL) == -1) { /* Mutex initialization failed, free the key and created owner */ Mem_Free(pkey); Mem_Free(pclient); return NULL; } /* Ref count the NSM Client as being used by this NLM Client */ inc_nsm_client_ref(pnsm_client); if(nlm_client_Set(pkey, pclient) == 1) { if(isFullDebug(COMPONENT_STATE)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_nlm_client(pclient, str); LogFullDebug(COMPONENT_STATE, "Set NLM Client {%s}", str); } if(care != CARE_MONITOR || nsm_monitor(pnsm_client)) return pclient; dec_nlm_client_ref(pclient); return NULL; } dec_nsm_client_ref(pnsm_client); Mem_Free(pkey); Mem_Free(pclient); return NULL; }
int nlm4_Unlock(nfs_arg_t * parg /* IN */ , exportlist_t * pexport /* IN */ , fsal_op_context_t * pcontext /* IN */ , cache_inode_client_t * pclient /* INOUT */ , hash_table_t * ht /* INOUT */ , struct svc_req *preq /* IN */ , nfs_res_t * pres /* OUT */ ) { nlm4_unlockargs * arg = &parg->arg_nlm4_unlock; cache_entry_t * pentry; state_status_t state_status = CACHE_INODE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2]; state_nsm_client_t * nsm_client; state_nlm_client_t * nlm_client; state_owner_t * nlm_owner; state_lock_desc_t lock; int rc; netobj_to_string(&arg->cookie, buffer, sizeof(buffer)); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Unlock svid=%d off=%llx len=%llx cookie=%s", (int) arg->alock.svid, (unsigned long long) arg->alock.l_offset, (unsigned long long) arg->alock.l_len, buffer); if(!copy_netobj(&pres->res_nlm4test.cookie, &arg->cookie)) { pres->res_nlm4.stat.stat = NLM4_FAILED; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } if(in_nlm_grace_period()) { pres->res_nlm4.stat.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } rc = nlm_process_parameters(preq, FALSE, /* exlcusive doesn't matter */ &arg->alock, &lock, ht, &pentry, pcontext, pclient, CARE_NOT, /* unlock doesn't care if owner is found */ &nsm_client, &nlm_client, &nlm_owner, NULL); if(rc >= 0) { /* Present the error back to the client */ pres->res_nlm4.stat.stat = (nlm4_stats)rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; } if(state_unlock(pentry, pcontext, nlm_owner, NULL, &lock, pclient, &state_status) != STATE_SUCCESS) { /* Unlock could fail in the FSAL and make a bit of a mess, especially if * we are in out of memory situation. Such an error is logged by * Cache Inode. */ pres->res_nlm4test.test_stat.stat = nlm_convert_state_error(state_status); } else { pres->res_nlm4.stat.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner, pclient); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Unlock %s", lock_result_str(pres->res_nlm4.stat.stat)); return NFS_REQ_OK; }
int nlm4_Share(nfs_arg_t *args, struct svc_req *req, nfs_res_t *res) { nlm4_shareargs *arg = &args->arg_nlm4_share; struct fsal_obj_handle *obj; state_status_t state_status = STATE_SUCCESS; char buffer[MAXNETOBJ_SZ * 2]; state_nsm_client_t *nsm_client; state_nlm_client_t *nlm_client; state_owner_t *nlm_owner; state_t *nlm_state; int rc; int grace = nfs_in_grace(); /* Indicate if we let FSAL to handle requests during grace. */ bool_t fsal_grace = false; /* NLM doesn't have a BADHANDLE error, nor can rpc_execute deal with * responding to an NLM_*_MSG call, so we check here if the export is * NULL and if so, handle the response. */ if (op_ctx->ctx_export == NULL) { res->res_nlm4share.stat = NLM4_STALE_FH; LogInfo(COMPONENT_NLM, "INVALID HANDLE: nlm4_Share"); return NFS_REQ_OK; } res->res_nlm4share.sequence = 0; netobj_to_string(&arg->cookie, buffer, 1024); LogDebug(COMPONENT_NLM, "REQUEST PROCESSING: Calling nlm4_Share cookie=%s reclaim=%s", buffer, arg->reclaim ? "yes" : "no"); copy_netobj(&res->res_nlm4share.cookie, &arg->cookie); /* Allow only reclaim share request during recovery and visa versa. * Note: NLM_SHARE is indicated to be non-monitored, however, it does * have a reclaim flag, so we will honor the reclaim flag if used. */ if (grace) { if (op_ctx->fsal_export->exp_ops. fs_supports(op_ctx->fsal_export, fso_grace_method)) fsal_grace = true; if (!fsal_grace && !arg->reclaim) { res->res_nlm4share.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(res->res_nlm4share.stat)); return NFS_REQ_OK; } } else if (arg->reclaim) { res->res_nlm4share.stat = NLM4_DENIED_GRACE_PERIOD; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(res->res_nlm4share.stat)); return NFS_REQ_OK; } rc = nlm_process_share_parms(req, &arg->share, op_ctx->fsal_export, &obj, CARE_NO_MONITOR, &nsm_client, &nlm_client, &nlm_owner, &nlm_state); if (rc >= 0) { /* Present the error back to the client */ res->res_nlm4share.stat = (nlm4_stats) rc; LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(res->res_nlm4share.stat)); return NFS_REQ_OK; } state_status = state_nlm_share(obj, arg->share.access, arg->share.mode, nlm_owner, nlm_state, grace); if (state_status != STATE_SUCCESS) { res->res_nlm4share.stat = nlm_convert_state_error(state_status); } else { res->res_nlm4share.stat = NLM4_GRANTED; } /* Release the NLM Client and NLM Owner references we have */ dec_nsm_client_ref(nsm_client); dec_nlm_client_ref(nlm_client); dec_state_owner_ref(nlm_owner); obj->obj_ops.put_ref(obj); dec_nlm_state_ref(nlm_state); LogDebug(COMPONENT_NLM, "REQUEST RESULT: nlm4_Share %s", lock_result_str(res->res_nlm4share.stat)); return NFS_REQ_OK; }