Esempio n. 1
0
/*ARGSUSED*/
uint_t
xc_serv(caddr_t arg1, caddr_t arg2)
{
	struct machcpu *mcpup = &(CPU->cpu_m);
	xc_msg_t *msg;
	xc_data_t *data;
	xc_msg_t *xc_waiters = NULL;
	uint32_t num_waiting = 0;
	xc_func_t func;
	xc_arg_t a1;
	xc_arg_t a2;
	xc_arg_t a3;
	uint_t rc = DDI_INTR_UNCLAIMED;

	while (mcpup->xc_work_cnt != 0) {
		rc = DDI_INTR_CLAIMED;

		/*
		 * We may have to wait for a message to arrive.
		 */
		for (msg = NULL; msg == NULL;
		    msg = xc_extract(&mcpup->xc_msgbox)) {

			/*
			 * Alway check for and handle a priority message.
			 */
			if (BT_TEST(xc_priority_set, CPU->cpu_id)) {
				func = xc_priority_data.xc_func;
				a1 = xc_priority_data.xc_a1;
				a2 = xc_priority_data.xc_a2;
				a3 = xc_priority_data.xc_a3;
				XC_BT_CLEAR(xc_priority_set, CPU->cpu_id);
				xc_decrement(mcpup);
				func(a1, a2, a3);
				if (mcpup->xc_work_cnt == 0)
					return (rc);
			}

			/*
			 * wait for a message to arrive
			 */
			SMT_PAUSE();
		}


		/*
		 * process the message
		 */
		switch (msg->xc_command) {

		/*
		 * ASYNC gives back the message immediately, then we do the
		 * function and return with no more waiting.
		 */
		case XC_MSG_ASYNC:
			data = &cpu[msg->xc_master]->cpu_m.xc_data;
			func = data->xc_func;
			a1 = data->xc_a1;
			a2 = data->xc_a2;
			a3 = data->xc_a3;
			msg->xc_command = XC_MSG_DONE;
			xc_insert(&cpu[msg->xc_master]->cpu_m.xc_msgbox, msg);
			if (func != NULL)
				(void) (*func)(a1, a2, a3);
			xc_decrement(mcpup);
			break;

		/*
		 * SYNC messages do the call, then send it back to the master
		 * in WAITING mode
		 */
		case XC_MSG_SYNC:
			data = &cpu[msg->xc_master]->cpu_m.xc_data;
			if (data->xc_func != NULL)
				(void) (*data->xc_func)(data->xc_a1,
				    data->xc_a2, data->xc_a3);
			msg->xc_command = XC_MSG_WAITING;
			xc_insert(&cpu[msg->xc_master]->cpu_m.xc_msgbox, msg);
			break;

		/*
		 * WAITING messsages are collected by the master until all
		 * have arrived. Once all arrive, we release them back to
		 * the slaves
		 */
		case XC_MSG_WAITING:
			xc_insert(&xc_waiters, msg);
			if (++num_waiting < mcpup->xc_wait_cnt)
				break;
			while ((msg = xc_extract(&xc_waiters)) != NULL) {
				msg->xc_command = XC_MSG_RELEASED;
				xc_insert(&cpu[msg->xc_slave]->cpu_m.xc_msgbox,
				    msg);
				--num_waiting;
			}
			if (num_waiting != 0)
				panic("wrong number waiting");
			mcpup->xc_wait_cnt = 0;
			break;

		/*
		 * CALL messages do the function and then, like RELEASE,
		 * send the message is back to master as DONE.
		 */
		case XC_MSG_CALL:
			data = &cpu[msg->xc_master]->cpu_m.xc_data;
			if (data->xc_func != NULL)
				(void) (*data->xc_func)(data->xc_a1,
				    data->xc_a2, data->xc_a3);
			/*FALLTHROUGH*/
		case XC_MSG_RELEASED:
			msg->xc_command = XC_MSG_DONE;
			xc_insert(&cpu[msg->xc_master]->cpu_m.xc_msgbox, msg);
			xc_decrement(mcpup);
			break;

		/*
		 * DONE means a slave has completely finished up.
		 * Once we collect all the DONE messages, we'll exit
		 * processing too.
		 */
		case XC_MSG_DONE:
			msg->xc_command = XC_MSG_FREE;
			xc_insert(&mcpup->xc_free, msg);
			xc_decrement(mcpup);
			break;

		case XC_MSG_FREE:
			panic("free message 0x%p in msgbox", (void *)msg);
			break;

		default:
			panic("bad message 0x%p in msgbox", (void *)msg);
			break;
		}
	}
	return (rc);
}
Esempio n. 2
0
static int
dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
{
	dtrace_hdl_t *dtp = ddo->ddo_hdl;
	dof_provider_t dofpv;
	dof_relohdr_t dofr;
	dof_secidx_t *dofs;
	ulong_t xr, nxr;
	size_t sz;
	id_t i;

	if (pvp->pv_flags & DT_PROVIDER_IMPL) {
		/*
		 * ignore providers that are exported by dtrace(7D)
		 */
		return (0);
	}

	nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);
	dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));
	xr = 1; /* reserve dofs[0] for the provider itself */

	/*
	 * For each translator referenced by the provider (pv_xrefs), emit an
	 * exported translator section for it if one hasn't been created yet.
	 */
	for (i = 0; i < pvp->pv_xrmax; i++) {
		if (BT_TEST(pvp->pv_xrefs, i) &&
		    dtp->dt_xlatemode == DT_XL_DYNAMIC) {
			dof_add_translator(ddo,
			    dt_xlator_lookup_id(dtp, i), DOF_SECT_XLEXPORT);
			dofs[xr++] = ddo->ddo_xlexport[i];
		}
	}

	dt_buf_reset(dtp, &ddo->ddo_probes);
	dt_buf_reset(dtp, &ddo->ddo_args);
	dt_buf_reset(dtp, &ddo->ddo_offs);
	dt_buf_reset(dtp, &ddo->ddo_enoffs);
	dt_buf_reset(dtp, &ddo->ddo_rels);

	(void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo);

	if (dt_buf_len(&ddo->ddo_probes) == 0)
		return (dt_set_errno(dtp, EDT_NOPROBES));

	dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,
	    sizeof (uint64_t), 0, sizeof (dof_probe_t),
	    dt_buf_len(&ddo->ddo_probes));

	dt_buf_concat(dtp, &ddo->ddo_ldata,
	    &ddo->ddo_probes, sizeof (uint64_t));

	dofpv.dofpv_prargs = dof_add_lsect(ddo, NULL, DOF_SECT_PRARGS,
	    sizeof (uint8_t), 0, sizeof (uint8_t), dt_buf_len(&ddo->ddo_args));

	dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t));

	dofpv.dofpv_proffs = dof_add_lsect(ddo, NULL, DOF_SECT_PROFFS,
	    sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_offs));

	dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_offs, sizeof (uint_t));

	if ((sz = dt_buf_len(&ddo->ddo_enoffs)) != 0) {
		dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL,
		    DOF_SECT_PRENOFFS, sizeof (uint_t), 0, sizeof (uint_t), sz);
	} else {
		dofpv.dofpv_prenoffs = DOF_SECT_NONE;
	}

	dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_enoffs, sizeof (uint_t));

	dofpv.dofpv_strtab = ddo->ddo_strsec;
	dofpv.dofpv_name = dof_add_string(ddo, pvp->pv_desc.dtvd_name);

	dofpv.dofpv_provattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_provider);
	dofpv.dofpv_modattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_mod);
	dofpv.dofpv_funcattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_func);
	dofpv.dofpv_nameattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_name);
	dofpv.dofpv_argsattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_args);

	dofs[0] = dof_add_lsect(ddo, &dofpv, DOF_SECT_PROVIDER,
	    sizeof (dof_secidx_t), 0, 0, sizeof (dof_provider_t));

	dofr.dofr_strtab = dofpv.dofpv_strtab;
	dofr.dofr_tgtsec = dofpv.dofpv_probes;
	dofr.dofr_relsec = dof_add_lsect(ddo, NULL, DOF_SECT_RELTAB,
	    sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
	    dt_buf_len(&ddo->ddo_rels));

	dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_rels, sizeof (uint64_t));

	(void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,
	    sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));

	if (nxr != 0 && dtp->dt_xlatemode == DT_XL_DYNAMIC) {
		(void) dof_add_lsect(ddo, dofs, DOF_SECT_PREXPORT,
		    sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),
		    sizeof (dof_secidx_t) * (nxr + 1));
	}

	return (0);
}
Esempio n. 3
0
/*
 * Accumulate media entries from recycler's dat file.
 */
int
DatAccumulate(
    CsdEntry_t *csd)
{
    size_t size;
    MediaTable_t *dat_table;
    MediaEntry_t *datfile_cache;
    MediaEntry_t *vsn;
    MediaEntry_t *datfile;	/* vsn entry from dat file */
    MediaEntry_t *dat;	/* vsn entry in samfs dump's dat table */
    size_t ngot;
    int i;
    int idx;
    int num_inodes;
    DatTable_t table;
    int rval;
    off_t pos;
    char *path;
    int fd;

    path = csd->ce_datPath;		/* path to dat file */
    fd = readOpen(path);		/* open file descriptor for dat file */
    if (fd < 0) {
        Trace(TR_MISC, "%s '%s', dat file open failed, errno= %d",
              errmsg1, path, errno);
        return (-1);
    }
    dat_table = csd->ce_table;	/* media table generated for dat file */

    /*
     * Need to search from the beginning.  Rewind dat file and
     * the read header again.
     */
    rval = readHeader(fd, path);
    if (rval != 0) {
        Trace(TR_MISC, "%s '%s', dat table header read failed",
              errmsg1, path);
        DatClose(fd);
        return (-1);
    }

    num_inodes = 0;

    /*
     * Read datfile table entries until we find the entry we are
     * currently processing.
     */
    while (InfiniteLoop) {
        datfile_cache = NULL;

        ngot = read(fd, &table, sizeof (DatTable_t));
        if (ngot != sizeof (DatTable_t)) {
            Trace(TR_MISC, "%s '%s', dat table read failed",
                  errmsg1, path);
            DatClose(fd);
            return (-1);
        }

        if (table.dt_mapmin != dat_table->mt_mapmin) {
            continue;
        }
        if (table.dt_mapchunk != dat_table->mt_mapchunk) {
            Trace(TR_MISC, "%s '%s', map chunk does not match",
                  errmsg1, path);
            DatClose(fd);
            return (-1);
        }

        pos = lseek(fd, 0, SEEK_CUR);

        Trace(TR_MISC, "[%s] Read dat entries 0x%lx "
              "count: %d seqnum candidates: %lld-%lld",
              dat_table->mt_name, pos, table.dt_count, table.dt_mapmin,
              table.dt_mapmin + table.dt_mapchunk - 1);

        size = table.dt_count * sizeof (MediaEntry_t);
        SamMalloc(datfile_cache, size);
        (void) memset(datfile_cache, 0, size);

        for (i = 0; i < table.dt_count; i++) {
            datfile = &datfile_cache[i];

            ngot = read(fd, datfile, sizeof (MediaEntry_t));
            if (ngot != sizeof (MediaEntry_t)) {
                Trace(TR_MISC, "%s '%s', header read error "
                      "read: %d expected: %d, errno= %d",
                      errmsg1, path,
                      ngot, sizeof (MediaEntry_t), errno);
                num_inodes = -1;
                goto out;
            }

            if ((datfile->me_type == DT_DISK) &&
                    (datfile->me_mapsize != 0)) {
                SamMalloc(datfile->me_bitmap,
                          datfile->me_mapsize);
                (void) memset(datfile->me_bitmap, 0,
                              datfile->me_mapsize);

                ngot = read(fd, datfile->me_bitmap,
                            datfile->me_mapsize);
                if (ngot != datfile->me_mapsize) {
                    Trace(TR_MISC,
                          "%s '%s', bitmap read error "
                          "read: %d expected: %d, errno= %d",
                          errmsg1, path, ngot,
                          datfile->me_mapsize, errno);
                    num_inodes = -1;
                    goto out;
                }
            }

            vsn = MediaFind(&ArchMedia,
                            datfile->me_type, datfile->me_name);
            if (vsn == NULL) {
                Trace(TR_MISC,
                      "%s '%s', failed to find vsn %s.%s",
                      errmsg1, path,
                      sam_mediatoa(datfile->me_type),
                      datfile->me_name);
                num_inodes = -1;
                goto out;
            }

            /*
             * For completeness, update in-memory's dat_table for
             * samfs dump file.  This is not really necessary but
             * might be useful for debugging purposes.
             */
            dat = NULL;
            if (dat_table != NULL) {
                dat = MediaFind(dat_table, datfile->me_type,
                                datfile->me_name);
                if (dat == NULL) {
                    Trace(TR_MISC,
                          "Error failed to find vsn %s.%s",
                          sam_mediatoa(datfile->me_type),
                          datfile->me_name);
                    num_inodes = -1;
                    goto out;
                }
            }

            Trace(TR_SAMDEV,
                  "[%s.%s] Accumulate dat active files: %d",
                  sam_mediatoa(vsn->me_type), vsn->me_name,
                  datfile->me_files);

            PthreadMutexLock(&vsn->me_mutex);
            vsn->me_files += datfile->me_files;
            PthreadMutexUnlock(&vsn->me_mutex);

            if (dat != NULL) {
                PthreadMutexLock(&dat->me_mutex);
                dat->me_files += datfile->me_files;
                PthreadMutexUnlock(&dat->me_mutex);
            }

            num_inodes += datfile->me_files;

            if ((datfile->me_type == DT_DISK) &&
                    (datfile->me_mapsize != 0)) {

                for (idx = 0;
                        idx <= dat_table->mt_mapchunk; idx++) {

                    /* FIXME */
                    if (BT_TEST(datfile->me_bitmap, idx) == 1) {
                        PthreadMutexLock(&vsn->me_mutex);
                        BT_SET(vsn->me_bitmap, idx);
                        PthreadMutexUnlock(&vsn->me_mutex);

                        if (dat != NULL) {
                            PthreadMutexLock(&dat->me_mutex);
                            BT_SET(dat->me_bitmap, idx);
                            PthreadMutexUnlock(&dat->me_mutex);
                        }
                    }
                }
            }

            /*
             * Free memory allocated for bitmap read from disk.
             */
            if (datfile->me_bitmap != NULL) {
                SamFree(datfile->me_bitmap);
                datfile->me_bitmap = NULL;
            }
        }
        break;
    }

out:
    if (datfile_cache != NULL) {
        SamFree(datfile_cache);
        for (i = 0; i < table.dt_count; i++) {
            datfile = &datfile_cache[i];
            if (datfile->me_bitmap != NULL) {
                SamFree(datfile->me_bitmap);
                datfile->me_bitmap = NULL;
            }
        }
    }
    DatClose(fd);
    return (num_inodes);
}
Esempio n. 4
0
void
exacct_calculate_proc_usage(proc_t *p, proc_usage_t *pu, ulong_t *mask,
    int flag, int wstat)
{
	timestruc_t ts, ts_run;

	ASSERT(MUTEX_HELD(&p->p_lock));

	/*
	 * Convert CPU and execution times to sec/nsec format.
	 */
	if (BT_TEST(mask, AC_PROC_CPU)) {
		hrt2ts(mstate_aggr_state(p, LMS_USER), &ts);
		pu->pu_utimesec = (uint64_t)(ulong_t)ts.tv_sec;
		pu->pu_utimensec = (uint64_t)(ulong_t)ts.tv_nsec;
		hrt2ts(mstate_aggr_state(p, LMS_SYSTEM), &ts);
		pu->pu_stimesec = (uint64_t)(ulong_t)ts.tv_sec;
		pu->pu_stimensec = (uint64_t)(ulong_t)ts.tv_nsec;
	}
	if (BT_TEST(mask, AC_PROC_TIME)) {
		gethrestime(&ts);
		pu->pu_finishsec = (uint64_t)(ulong_t)ts.tv_sec;
		pu->pu_finishnsec = (uint64_t)(ulong_t)ts.tv_nsec;
		hrt2ts(gethrtime() - p->p_mstart, &ts_run);
		ts.tv_sec -= ts_run.tv_sec;
		ts.tv_nsec -= ts_run.tv_nsec;
		if (ts.tv_nsec < 0) {
			ts.tv_sec--;
			if ((ts.tv_nsec = ts.tv_nsec + NANOSEC) >= NANOSEC) {
				ts.tv_sec++;
				ts.tv_nsec -= NANOSEC;
			}
		}
		pu->pu_startsec = (uint64_t)(ulong_t)ts.tv_sec;
		pu->pu_startnsec = (uint64_t)(ulong_t)ts.tv_nsec;
	}

	pu->pu_pid = p->p_pidp->pid_id;
	pu->pu_acflag = p->p_user.u_acflag;
	pu->pu_projid = p->p_task->tk_proj->kpj_id;
	pu->pu_taskid = p->p_task->tk_tkid;
	pu->pu_major = getmajor(p->p_sessp->s_dev);
	pu->pu_minor = getminor(p->p_sessp->s_dev);
	pu->pu_ancpid = p->p_ancpid;
	pu->pu_wstat = wstat;
	/*
	 * Compute average RSS in K.  The denominator is the number of
	 * samples:  the number of clock ticks plus the initial value.
	 */
	pu->pu_mem_rss_avg = (PTOU(p)->u_mem / (p->p_stime + p->p_utime + 1)) *
	    (PAGESIZE / 1024);
	pu->pu_mem_rss_max = PTOU(p)->u_mem_max * (PAGESIZE / 1024);

	mutex_enter(&p->p_crlock);
	pu->pu_ruid = crgetruid(p->p_cred);
	pu->pu_rgid = crgetrgid(p->p_cred);
	mutex_exit(&p->p_crlock);

	bcopy(p->p_user.u_comm, pu->pu_command, strlen(p->p_user.u_comm) + 1);
	bcopy(p->p_zone->zone_name, pu->pu_zonename,
	    strlen(p->p_zone->zone_name) + 1);
	bcopy(p->p_zone->zone_nodename, pu->pu_nodename,
	    strlen(p->p_zone->zone_nodename) + 1);

	/*
	 * Calculate microstate accounting data for a process that is still
	 * running.  Presently, we explicitly collect all of the LWP usage into
	 * the proc usage structure here.
	 */
	if (flag & EW_PARTIAL)
		exacct_calculate_proc_mstate(p, pu);
	if (flag & EW_FINAL)
		exacct_copy_proc_mstate(p, pu);
}
Esempio n. 5
0
/*ARGSUSED*/
static faultcode_t
segkmem_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t size,
	enum fault_type type, enum seg_rw rw)
{
	pgcnt_t npages;
	spgcnt_t pg;
	page_t *pp;
	struct vnode *vp = seg->s_data;

	ASSERT(RW_READ_HELD(&seg->s_as->a_lock));

	if (seg->s_as != &kas || size > seg->s_size ||
	    addr < seg->s_base || addr + size > seg->s_base + seg->s_size)
		panic("segkmem_fault: bad args");

	/*
	 * If it is one of segkp pages, call segkp_fault.
	 */
	if (segkp_bitmap && seg == &kvseg &&
	    BT_TEST(segkp_bitmap, btop((uintptr_t)(addr - seg->s_base))))
		return (SEGOP_FAULT(hat, segkp, addr, size, type, rw));

	if (rw != S_READ && rw != S_WRITE && rw != S_OTHER)
		return (FC_NOSUPPORT);

	npages = btopr(size);

	switch (type) {
	case F_SOFTLOCK:	/* lock down already-loaded translations */
		for (pg = 0; pg < npages; pg++) {
			pp = page_lookup(vp, (u_offset_t)(uintptr_t)addr,
			    SE_SHARED);
			if (pp == NULL) {
				/*
				 * Hmm, no page. Does a kernel mapping
				 * exist for it?
				 */
				if (!hat_probe(kas.a_hat, addr)) {
					addr -= PAGESIZE;
					while (--pg >= 0) {
						pp = page_find(vp, (u_offset_t)
						    (uintptr_t)addr);
						if (pp)
							page_unlock(pp);
						addr -= PAGESIZE;
					}
					return (FC_NOMAP);
				}
			}
			addr += PAGESIZE;
		}
		if (rw == S_OTHER)
			hat_reserve(seg->s_as, addr, size);
		return (0);
	case F_SOFTUNLOCK:
		while (npages--) {
			pp = page_find(vp, (u_offset_t)(uintptr_t)addr);
			if (pp)
				page_unlock(pp);
			addr += PAGESIZE;
		}
		return (0);
	default:
		return (FC_NOSUPPORT);
	}
	/*NOTREACHED*/
}
Esempio n. 6
0
/*
 * Install/uninstall ACPI system event handler for child objects of hdl.
 * Return DDI_SUCCESS on success, and DDI_FAILURE on failure.
 */
static int
acpinex_event_walk(boolean_t init, acpinex_softstate_t *sp, ACPI_HANDLE hdl)
{
	int rc;
	int retval = DDI_SUCCESS;
	dev_info_t *dip;
	ACPI_HANDLE child = NULL;
	ACPI_OBJECT_TYPE type;
	ACPI_DEVICE_INFO *infop;
	acpidev_data_handle_t dhdl;

	/* Walk all child objects. */
	ASSERT(hdl != NULL);
	while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_ANY, hdl, child,
	    &child))) {
		/* Skip unwanted object types. */
		if (ACPI_FAILURE(AcpiGetType(child, &type)) ||
		    type > ACPI_TYPE_NS_NODE_MAX ||
		    BT_TEST(acpinex_object_type_mask, type) == 0) {
			continue;
		}

		/* Get data associated with the object. Skip it if fails. */
		dhdl = acpidev_data_get_handle(child);
		if (dhdl == NULL) {
			ACPINEX_DEBUG(CE_NOTE, "!acpinex: failed to get data "
			    "associated with %p, skip.", child);
			continue;
		}

		/* Query ACPI object info for the object. */
		if (ACPI_FAILURE(AcpiGetObjectInfo(child, &infop))) {
			cmn_err(CE_WARN,
			    "!acpidnex: failed to get object info for %p.",
			    child);
			continue;
		}

		if (init) {
			rc = acpinex_event_install_handler(child, sp, infop,
			    dhdl);
			if (rc != DDI_SUCCESS) {
				ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to "
				    "install handler for child %p of %s.",
				    child, sp->ans_path);
				retval = DDI_FAILURE;
			/*
			 * Try to handle descendants if both of the
			 * following two conditions are true:
			 * 1) Device corresponding to the current object is
			 *    enabled. If the device is absent/disabled,
			 *    no notification should be generated from
			 *    descendant objects of it.
			 * 2) No Solaris device node has been created for the
			 *    current object yet. If the device node has been
			 *    created for the current object, notification
			 *    events from child objects should be handled by
			 *    the corresponding driver.
			 */
			} else if (acpidev_check_device_enabled(
			    acpidev_data_get_status(dhdl)) &&
			    ACPI_FAILURE(acpica_get_devinfo(child, &dip))) {
				rc = acpinex_event_walk(B_TRUE, sp, child);
				if (rc != DDI_SUCCESS) {
					ACPINEX_DEBUG(CE_WARN,
					    "!acpinex: failed to install "
					    "handler for descendants of %s.",
					    sp->ans_path);
					retval = DDI_FAILURE;
				}
			}
		} else {
			rc = DDI_SUCCESS;
			/* Uninstall handler for descendants if needed. */
			if (ACPI_FAILURE(acpica_get_devinfo(child, &dip))) {
				rc = acpinex_event_walk(B_FALSE, sp, child);
			}
			if (rc == DDI_SUCCESS) {
				rc = acpinex_event_uninstall_handler(child,
				    infop, dhdl);
			}
			/* Undo will be done by caller in case of failure. */
			if (rc != DDI_SUCCESS) {
				ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to "
				    "uninstall handler for descendants of %s.",
				    sp->ans_path);
				AcpiOsFree(infop);
				retval = DDI_FAILURE;
				break;
			}
		}

		/* Release cached resources. */
		AcpiOsFree(infop);
	}

	return (retval);
}