/** * @brief Deep-free a duplicate request cache entry. * * If the entry has processed request data, the corresponding free * function is called on the result. The cache entry is then returned * to the dupreq_pool. */ static inline void nfs_dupreq_free_dupreq(dupreq_entry_t *dv) { const nfs_function_desc_t *func; if (dv->res) { func = nfs_dupreq_func(dv); func->free_function(dv->res); free_nfs_res(dv->res); } PTHREAD_MUTEX_destroy(&dv->mtx); pool_free(dupreq_pool, dv); }
/** * @brief Decrement the call path refcnt on a cache entry. * * We assert req->rq_u1 now points to the corresonding duplicate request * cache entry (dv). * * In the common case, a refcnt of 0 indicates that dv is cached. If * also dv->state == DUPREQ_DELETED, the request entry has been discarded * and should be destroyed here. * * @param[in] req The svc_req structure. * @param[in] func The function descriptor for this request type */ void nfs_dupreq_rele(struct svc_req *req, const nfs_function_desc_t *func) { dupreq_entry_t *dv = (dupreq_entry_t *) req->rq_u1; /* no-cache cleanup */ if (dv == (void *)DUPREQ_NOCACHE) { LogFullDebug(COMPONENT_DUPREQ, "releasing no-cache res %p", req->rq_u2); func->free_function(req->rq_u2); free_nfs_res(req->rq_u2); goto out; } pthread_mutex_lock(&dv->mtx); LogFullDebug(COMPONENT_DUPREQ, "releasing dv=%p xid=%u on DRC=%p state=%s, " "refcnt=%d", dv, dv->hin.tcp.rq_xid, dv->hin.drc, dupreq_state_table[dv->state], dv->refcnt); (dv->refcnt)--; if (dv->refcnt == 0) { if (dv->state == DUPREQ_DELETED) { pthread_mutex_unlock(&dv->mtx); /* deep free */ nfs_dupreq_free_dupreq(dv); return; } } pthread_mutex_unlock(&dv->mtx); out: /* dispose RPC header */ if (req->rq_auth) SVCAUTH_RELEASE(req->rq_auth, req); /* XXX */ if (req->rq_rtaddr.len) mem_free(req->rq_rtaddr.buf, req->rq_rtaddr.len); (void)free_rpc_msg(req->rq_msg); return; }