/* * Send a notification to a client immediately after it registers. * The result_t is a list of all the nodes that match their specified * nodes of interest, all returned on the added list. This serves * as a base of reference to the client. All future MD updates are * relative to this list. */ static int mdeg_notify_client_reg(mdeg_clnt_t *clnt) { md_t *mdp = NULL; mde_str_cookie_t nname; mde_str_cookie_t aname; mde_cookie_t startnode; int nnodes; int nodechk; mde_cookie_t *listp = NULL; mdeg_result_t *mdeg_res = NULL; int rv = MDEG_SUCCESS; mutex_enter(&mdeg.lock); /* * Handle the special case where the node specification * is NULL. In this case, call the client callback without * any results. All processing is left to the client. */ if (clnt->pspec == NULL) { /* call the client callback */ (*clnt->cb)(clnt->cb_arg, NULL); goto done; } if ((mdp = md_get_handle()) == NULL) { cmn_err(CE_WARN, "unable to retrieve current MD"); rv = MDEG_FAILURE; goto done; } startnode = mdeg_find_start_node(mdp, clnt->pspec); if (startnode == MDE_INVAL_ELEM_COOKIE) { /* not much we can do */ cmn_err(CE_WARN, "unable to match node specifier"); rv = MDEG_FAILURE; goto done; } /* * Use zalloc to provide correct default values for the * unused removed, match_prev, and match_curr lists. */ mdeg_res = kmem_zalloc(sizeof (mdeg_result_t), KM_SLEEP); nname = md_find_name(mdp, clnt->nmatch->namep); aname = md_find_name(mdp, "fwd"); nnodes = md_scan_dag(mdp, startnode, nname, aname, NULL); if (nnodes == 0) { MDEG_DBG("mdeg_notify_client_reg: no nodes of interest\n"); rv = MDEG_SUCCESS; goto done; } else if (nnodes == -1) { MDEG_DBG("error scanning DAG\n"); rv = MDEG_FAILURE; goto done; } MDEG_DBG("mdeg_notify_client_reg: %d node%s of interest\n", nnodes, (nnodes == 1) ? "" : "s"); /* get the list of nodes of interest */ listp = kmem_alloc(sizeof (mde_cookie_t) * nnodes, KM_SLEEP); nodechk = md_scan_dag(mdp, startnode, nname, aname, listp); ASSERT(nodechk == nnodes); mdeg_res->added.mdp = mdp; mdeg_res->added.mdep = listp; mdeg_res->added.nelem = nnodes; /* call the client callback */ (*clnt->cb)(clnt->cb_arg, mdeg_res); done: mutex_exit(&mdeg.lock); if (mdp) (void) md_fini_handle(mdp); if (listp) kmem_free(listp, sizeof (mde_cookie_t) * nnodes); if (mdeg_res) kmem_free(mdeg_res, sizeof (mdeg_result_t)); return (rv); }
static void mdeg_notify_client(void *arg) { mdeg_clnt_t *clnt = (mdeg_clnt_t *)arg; md_diff_cookie_t mdd = MD_INVAL_DIFF_COOKIE; mdeg_result_t mdeg_res; mde_cookie_t md_prev_start; mde_cookie_t md_curr_start; /* * mdeg.rwlock must be held as a reader while this function * executes. However, we do not need to acquire the lock as a * reader here because it is held as a reader by the thread * executing mdeg_notify_clients which triggers the execution * of this function from a taskq. Since mdeg_notify_clients * holds the lock as a reader until the taskq callbacks have * completed, it will be held for the life of this function call. * Furthermore, we must not attempt to acquire the lock as a * reader with rw_enter because if there is a pending writer, * we will block, creating a circular deadlock with this function, * the writer, and mdeg_notify_clients. Since we do not need * to acquire the lock, just assert that it is held. */ ASSERT(RW_READ_HELD(&mdeg.rwlock)); if (!mdeg.enabled) { /* trying to shutdown */ MDEG_DBG("mdeg_notify_client: mdeg disabled, aborting\n"); goto cleanup; } /* * Handle the special case where the node specification * is NULL. In this case, call the client callback without * any results. All processing is left to the client. */ if (clnt->pspec == NULL) { /* call the client callback */ (*clnt->cb)(clnt->cb_arg, NULL); MDEG_DBG("MDEG client callback done\n"); goto cleanup; } /* find our start nodes */ md_prev_start = mdeg_find_start_node(mdeg.md_prev, clnt->pspec); if (md_prev_start == MDE_INVAL_ELEM_COOKIE) { goto cleanup; } md_curr_start = mdeg_find_start_node(mdeg.md_curr, clnt->pspec); if (md_curr_start == MDE_INVAL_ELEM_COOKIE) { goto cleanup; } /* diff the MDs */ mdd = md_diff_init(mdeg.md_prev, md_prev_start, mdeg.md_curr, md_curr_start, clnt->nmatch->namep, clnt->nmatch->matchp); if (mdd == MD_INVAL_DIFF_COOKIE) { MDEG_DBG("unable to diff MDs\n"); goto cleanup; } /* * Cache the results of the diff */ mdeg_get_diff_results(mdd, &mdeg_res); /* call the client callback */ (*clnt->cb)(clnt->cb_arg, &mdeg_res); MDEG_DBG("MDEG client callback done\n"); cleanup: if (mdd != MD_INVAL_DIFF_COOKIE) (void) md_diff_fini(mdd); }
static void mdeg_notify_client(void *arg) { mdeg_clnt_t *clnt = (mdeg_clnt_t *)arg; md_diff_cookie_t mdd = MD_INVAL_DIFF_COOKIE; mdeg_result_t mdeg_res; mde_cookie_t md_prev_start; mde_cookie_t md_curr_start; rw_enter(&mdeg.rwlock, RW_READER); if (!mdeg.enabled) { /* trying to shutdown */ MDEG_DBG("mdeg_notify_client: mdeg disabled, aborting\n"); goto cleanup; } /* * Handle the special case where the node specification * is NULL. In this case, call the client callback without * any results. All processing is left to the client. */ if (clnt->pspec == NULL) { /* call the client callback */ (*clnt->cb)(clnt->cb_arg, NULL); MDEG_DBG("MDEG client callback done\n"); goto cleanup; } /* find our start nodes */ md_prev_start = mdeg_find_start_node(mdeg.md_prev, clnt->pspec); if (md_prev_start == MDE_INVAL_ELEM_COOKIE) { goto cleanup; } md_curr_start = mdeg_find_start_node(mdeg.md_curr, clnt->pspec); if (md_curr_start == MDE_INVAL_ELEM_COOKIE) { goto cleanup; } /* diff the MDs */ mdd = md_diff_init(mdeg.md_prev, md_prev_start, mdeg.md_curr, md_curr_start, clnt->nmatch->namep, clnt->nmatch->matchp); if (mdd == MD_INVAL_DIFF_COOKIE) { MDEG_DBG("unable to diff MDs\n"); goto cleanup; } /* * Cache the results of the diff */ mdeg_get_diff_results(mdd, &mdeg_res); /* call the client callback */ (*clnt->cb)(clnt->cb_arg, &mdeg_res); MDEG_DBG("MDEG client callback done\n"); cleanup: rw_exit(&mdeg.rwlock); if (mdd != MD_INVAL_DIFF_COOKIE) (void) md_diff_fini(mdd); }