Home | History | Annotate | Download | only in ctfs
      1     0  stevel /*
      2     0  stevel  * CDDL HEADER START
      3     0  stevel  *
      4     0  stevel  * The contents of this file are subject to the terms of the
      5  3898     rsb  * Common Development and Distribution License (the "License").
      6  3898     rsb  * You may not use this file except in compliance with the License.
      7     0  stevel  *
      8     0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0  stevel  * or http://www.opensolaris.org/os/licensing.
     10     0  stevel  * See the License for the specific language governing permissions
     11     0  stevel  * and limitations under the License.
     12     0  stevel  *
     13     0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0  stevel  *
     19     0  stevel  * CDDL HEADER END
     20     0  stevel  */
     21     0  stevel /*
     22  3898     rsb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23     0  stevel  * Use is subject to license terms.
     24     0  stevel  */
     25     0  stevel 
     26     0  stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27     0  stevel 
     28     0  stevel #include <sys/types.h>
     29     0  stevel #include <sys/param.h>
     30     0  stevel #include <sys/time.h>
     31     0  stevel #include <sys/cred.h>
     32     0  stevel #include <sys/vfs.h>
     33  3898     rsb #include <sys/vfs_opreg.h>
     34     0  stevel #include <sys/gfs.h>
     35     0  stevel #include <sys/vnode.h>
     36     0  stevel #include <sys/systm.h>
     37     0  stevel #include <sys/errno.h>
     38     0  stevel #include <sys/sysmacros.h>
     39     0  stevel #include <fs/fs_subr.h>
     40     0  stevel #include <sys/contract.h>
     41     0  stevel #include <sys/contract_impl.h>
     42     0  stevel #include <sys/ctfs.h>
     43     0  stevel #include <sys/ctfs_impl.h>
     44     0  stevel #include <sys/file.h>
     45     0  stevel #include <sys/policy.h>
     46     0  stevel 
     47     0  stevel /*
     48     0  stevel  * CTFS routines for the /system/contract/<type>/bundle vnode.
     49     0  stevel  * CTFS routines for the /system/contract/<type>/pbundle vnode.
     50     0  stevel  * CTFS routines for the /system/contract/<type>/<ctid>/events vnode.
     51     0  stevel  */
     52     0  stevel 
     53     0  stevel /*
     54     0  stevel  * ctfs_endpoint_open
     55     0  stevel  *
     56     0  stevel  * Called by the VOP_OPEN entry points to perform some common checks
     57     0  stevel  * and set up the endpoint listener, if not already done.
     58     0  stevel  */
     59     0  stevel static int
     60     0  stevel ctfs_endpoint_open(ctfs_endpoint_t *endpt, ct_equeue_t *q, int flag)
     61     0  stevel {
     62     0  stevel 	if ((flag & ~FNONBLOCK) != (FREAD | FOFFMAX))
     63     0  stevel 		return (EINVAL);
     64     0  stevel 
     65     0  stevel 	mutex_enter(&endpt->ctfs_endpt_lock);
     66     0  stevel 	if ((endpt->ctfs_endpt_flags & CTFS_ENDPT_SETUP) == 0) {
     67     0  stevel 		endpt->ctfs_endpt_flags |= CTFS_ENDPT_SETUP;
     68     0  stevel 		if (flag & FNONBLOCK)
     69     0  stevel 			endpt->ctfs_endpt_flags |= CTFS_ENDPT_NBLOCK;
     70     0  stevel 		cte_add_listener(q, &endpt->ctfs_endpt_listener);
     71     0  stevel 	}
     72     0  stevel 	mutex_exit(&endpt->ctfs_endpt_lock);
     73     0  stevel 
     74     0  stevel 	return (0);
     75     0  stevel }
     76     0  stevel 
     77     0  stevel /*
     78     0  stevel  * ctfs_endpoint inactive
     79     0  stevel  *
     80     0  stevel  * Called by the VOP_INACTIVE entry points to perform common listener
     81     0  stevel  * cleanup.
     82     0  stevel  */
     83     0  stevel static void
     84     0  stevel ctfs_endpoint_inactive(ctfs_endpoint_t *endpt)
     85     0  stevel {
     86     0  stevel 	mutex_enter(&endpt->ctfs_endpt_lock);
     87     0  stevel 	if (endpt->ctfs_endpt_flags & CTFS_ENDPT_SETUP) {
     88     0  stevel 		endpt->ctfs_endpt_flags = 0;
     89     0  stevel 		cte_remove_listener(&endpt->ctfs_endpt_listener);
     90     0  stevel 	}
     91     0  stevel 	mutex_exit(&endpt->ctfs_endpt_lock);
     92     0  stevel }
     93     0  stevel 
     94     0  stevel /*
     95     0  stevel  * ctfs_endpoint_ioctl
     96     0  stevel  *
     97     0  stevel  * Implements the common VOP_IOCTL handling for the event endpoints.
     98     0  stevel  * rprivchk, if true, indicates that event receive requests should
     99     0  stevel  * check the provided credentials.  This distinction exists because
    100     0  stevel  * contract endpoints perform their privilege checks at open-time, and
    101     0  stevel  * process bundle queue listeners by definition may view all events
    102     0  stevel  * their queues contain.
    103     0  stevel  */
    104     0  stevel static int
    105     0  stevel ctfs_endpoint_ioctl(ctfs_endpoint_t *endpt, int cmd, intptr_t arg, cred_t *cr,
    106     0  stevel     zone_t *zone, int rprivchk)
    107     0  stevel {
    108     0  stevel 	uint64_t id, zuniqid;
    109     0  stevel 
    110     0  stevel 	zuniqid = zone->zone_uniqid;
    111     0  stevel 
    112     0  stevel 	switch (cmd) {
    113     0  stevel 	case CT_ERESET:
    114     0  stevel 		cte_reset_listener(&endpt->ctfs_endpt_listener);
    115     0  stevel 		break;
    116     0  stevel 	case CT_ERECV:
    117     0  stevel 		/*
    118     0  stevel 		 * We pass in NULL for the cred when reading from
    119     0  stevel 		 * process bundle queues and contract queues because
    120     0  stevel 		 * the privilege check was performed at open time.
    121     0  stevel 		 */
    122     0  stevel 		return (cte_get_event(&endpt->ctfs_endpt_listener,
    123     0  stevel 		    endpt->ctfs_endpt_flags & CTFS_ENDPT_NBLOCK,
    124     0  stevel 		    (void *)arg, rprivchk ? cr : NULL, zuniqid, 0));
    125     0  stevel 	case CT_ECRECV:
    126     0  stevel 		return (cte_get_event(&endpt->ctfs_endpt_listener,
    127     0  stevel 		    endpt->ctfs_endpt_flags & CTFS_ENDPT_NBLOCK,
    128     0  stevel 		    (void *)arg, rprivchk ? cr : NULL, zuniqid, 1));
    129     0  stevel 	case CT_ENEXT:
    130     0  stevel 		if (copyin((void *)arg, &id, sizeof (uint64_t)))
    131     0  stevel 			return (EFAULT);
    132     0  stevel 		return (cte_next_event(&endpt->ctfs_endpt_listener, id));
    133     0  stevel 	case CT_ERELIABLE:
    134     0  stevel 		return (cte_set_reliable(&endpt->ctfs_endpt_listener, cr));
    135     0  stevel 	default:
    136     0  stevel 		return (EINVAL);
    137     0  stevel 	}
    138     0  stevel 
    139     0  stevel 	return (0);
    140     0  stevel }
    141     0  stevel 
    142     0  stevel /*
    143     0  stevel  * ctfs_endpoint_poll
    144     0  stevel  *
    145     0  stevel  * Called by the VOP_POLL entry points.
    146     0  stevel  */
    147     0  stevel static int
    148     0  stevel ctfs_endpoint_poll(ctfs_endpoint_t *endpt, short events, int anyyet,
    149     0  stevel     short *reventsp, pollhead_t **php)
    150     0  stevel {
    151     0  stevel 	if ((events & POLLIN) && endpt->ctfs_endpt_listener.ctl_position) {
    152     0  stevel 		*reventsp = POLLIN;
    153     0  stevel 	} else {
    154     0  stevel 		*reventsp = 0;
    155     0  stevel 		if (!anyyet)
    156     0  stevel 			*php = &endpt->ctfs_endpt_listener.ctl_pollhead;
    157     0  stevel 	}
    158     0  stevel 
    159     0  stevel 	return (0);
    160     0  stevel }
    161     0  stevel 
    162     0  stevel /*
    163     0  stevel  * ctfs_create_evnode
    164     0  stevel  *
    165     0  stevel  * Creates and returns a new evnode.
    166     0  stevel  */
    167     0  stevel vnode_t *
    168     0  stevel ctfs_create_evnode(vnode_t *pvp)
    169     0  stevel {
    170     0  stevel 	vnode_t *vp;
    171     0  stevel 	ctfs_evnode_t *evnode;
    172     0  stevel 	ctfs_cdirnode_t *cdirnode = pvp->v_data;
    173     0  stevel 
    174     0  stevel 	vp = gfs_file_create(sizeof (ctfs_evnode_t), pvp, ctfs_ops_event);
    175     0  stevel 	evnode = vp->v_data;
    176     0  stevel 
    177     0  stevel 	/*
    178     0  stevel 	 * We transitively have a hold on the contract through our
    179     0  stevel 	 * parent directory.
    180     0  stevel 	 */
    181     0  stevel 	evnode->ctfs_ev_contract = cdirnode->ctfs_cn_contract;
    182     0  stevel 
    183     0  stevel 	return (vp);
    184     0  stevel }
    185     0  stevel 
    186     0  stevel /*
    187     0  stevel  * ctfs_ev_access - VOP_ACCESS entry point
    188     0  stevel  *
    189     0  stevel  * You only get to access event files for contracts you or your
    190     0  stevel  * effective user id owns, unless you have a privilege.
    191     0  stevel  */
    192     0  stevel /*ARGSUSED*/
    193     0  stevel static int
    194  5331     amw ctfs_ev_access(
    195  5331     amw 	vnode_t *vp,
    196  5331     amw 	int mode,
    197  5331     amw 	int flags,
    198  5331     amw 	cred_t *cr,
    199  5331     amw 	caller_context_t *cct)
    200     0  stevel {
    201     0  stevel 	ctfs_evnode_t *evnode = vp->v_data;
    202     0  stevel 	contract_t *ct = evnode->ctfs_ev_contract;
    203     0  stevel 	int error;
    204     0  stevel 
    205     0  stevel 	if (mode & (VWRITE | VEXEC))
    206     0  stevel 		return (EACCES);
    207     0  stevel 
    208     0  stevel 	if (error = secpolicy_contract_observer(cr, ct))
    209     0  stevel 		return (error);
    210     0  stevel 
    211     0  stevel 	return (0);
    212     0  stevel }
    213     0  stevel 
    214     0  stevel /*
    215     0  stevel  * ctfs_ev_open - VOP_OPEN entry point
    216     0  stevel  *
    217     0  stevel  * Performs the same privilege checks as ctfs_ev_access, and then calls
    218     0  stevel  * ctfs_endpoint_open to perform the common endpoint initialization.
    219     0  stevel  */
    220     0  stevel /* ARGSUSED */
    221     0  stevel static int
    222  5331     amw ctfs_ev_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *cct)
    223     0  stevel {
    224     0  stevel 	ctfs_evnode_t *evnode = (*vpp)->v_data;
    225     0  stevel 	contract_t *ct = evnode->ctfs_ev_contract;
    226     0  stevel 	int error;
    227     0  stevel 
    228     0  stevel 	if (error = secpolicy_contract_observer(cr, ct))
    229     0  stevel 		return (error);
    230     0  stevel 
    231     0  stevel 	/*
    232     0  stevel 	 * See comment in ctfs_bu_open.
    233     0  stevel 	 */
    234     0  stevel 	return (ctfs_endpoint_open(&evnode->ctfs_ev_listener,
    235     0  stevel 	    &evnode->ctfs_ev_contract->ct_events, flag));
    236     0  stevel }
    237     0  stevel 
    238     0  stevel /*
    239     0  stevel  * ctfs_ev_inactive - VOP_INACTIVE entry point
    240     0  stevel  */
    241     0  stevel /* ARGSUSED */
    242     0  stevel static void
    243  5331     amw ctfs_ev_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
    244     0  stevel {
    245     0  stevel 	ctfs_evnode_t *evnode;
    246     0  stevel 	vnode_t *pvp = gfs_file_parent(vp);
    247     0  stevel 
    248     0  stevel 	/*
    249     0  stevel 	 * We must destroy the endpoint before releasing the parent; otherwise
    250     0  stevel 	 * we will try to destroy a contract with active listeners.  To prevent
    251     0  stevel 	 * this, we grab an extra hold on the parent.
    252     0  stevel 	 */
    253     0  stevel 	VN_HOLD(pvp);
    254     0  stevel 	if ((evnode = gfs_file_inactive(vp)) != NULL) {
    255     0  stevel 		ctfs_endpoint_inactive(&evnode->ctfs_ev_listener);
    256     0  stevel 		kmem_free(evnode, sizeof (ctfs_evnode_t));
    257     0  stevel 	}
    258     0  stevel 	VN_RELE(pvp);
    259     0  stevel }
    260     0  stevel 
    261     0  stevel /*
    262     0  stevel  * ctfs_ev_getattr - VOP_GETATTR entry point
    263     0  stevel  */
    264     0  stevel /* ARGSUSED */
    265     0  stevel static int
    266  5331     amw ctfs_ev_getattr(
    267  5331     amw 	vnode_t *vp,
    268  5331     amw 	vattr_t *vap,
    269  5331     amw 	int flags,
    270  5331     amw 	cred_t *cr,
    271  5331     amw 	caller_context_t *ct)
    272     0  stevel {
    273     0  stevel 	ctfs_evnode_t *evnode = vp->v_data;
    274     0  stevel 
    275     0  stevel 	vap->va_type = VREG;
    276     0  stevel 	vap->va_mode = 0444;
    277     0  stevel 	vap->va_nlink = 1;
    278     0  stevel 	vap->va_size = 0;
    279     0  stevel 	vap->va_ctime = evnode->ctfs_ev_contract->ct_ctime;
    280     0  stevel 	mutex_enter(&evnode->ctfs_ev_contract->ct_events.ctq_lock);
    281     0  stevel 	vap->va_atime = vap->va_mtime =
    282     0  stevel 	    evnode->ctfs_ev_contract->ct_events.ctq_atime;
    283     0  stevel 	mutex_exit(&evnode->ctfs_ev_contract->ct_events.ctq_lock);
    284     0  stevel 	ctfs_common_getattr(vp, vap);
    285     0  stevel 
    286     0  stevel 	return (0);
    287     0  stevel }
    288     0  stevel 
    289     0  stevel /*
    290     0  stevel  * ctfs_ev_ioctl - VOP_IOCTL entry point
    291     0  stevel  */
    292     0  stevel /* ARGSUSED */
    293     0  stevel static int
    294  5331     amw ctfs_ev_ioctl(
    295  5331     amw 	vnode_t *vp,
    296  5331     amw 	int cmd,
    297  5331     amw 	intptr_t arg,
    298  5331     amw 	int flag,
    299  5331     amw 	cred_t *cr,
    300  5331     amw 	int *rvalp,
    301  5331     amw 	caller_context_t *ct)
    302     0  stevel {
    303     0  stevel 	ctfs_evnode_t *evnode = vp->v_data;
    304     0  stevel 
    305     0  stevel 	return (ctfs_endpoint_ioctl(&evnode->ctfs_ev_listener, cmd, arg, cr,
    306   789  ahrens 	    VTOZONE(vp), 0));
    307     0  stevel }
    308     0  stevel 
    309     0  stevel /*
    310     0  stevel  * ctfs_ev_poll - VOP_POLL entry point
    311     0  stevel  */
    312  5331     amw /*ARGSUSED*/
    313     0  stevel static int
    314  5331     amw ctfs_ev_poll(
    315  5331     amw 	vnode_t *vp,
    316  5331     amw 	short events,
    317  5331     amw 	int anyyet,
    318  5331     amw 	short *reventsp,
    319  5331     amw 	pollhead_t **php,
    320  5331     amw 	caller_context_t *ct)
    321     0  stevel {
    322     0  stevel 	ctfs_evnode_t *evnode = vp->v_data;
    323     0  stevel 
    324     0  stevel 	return (ctfs_endpoint_poll(&evnode->ctfs_ev_listener, events, anyyet,
    325     0  stevel 	    reventsp, php));
    326     0  stevel }
    327     0  stevel 
    328     0  stevel const fs_operation_def_t ctfs_tops_event[] = {
    329  3898     rsb 	{ VOPNAME_OPEN,		{ .vop_open = ctfs_ev_open } },
    330  3898     rsb 	{ VOPNAME_CLOSE,	{ .vop_close = ctfs_close } },
    331  3898     rsb 	{ VOPNAME_IOCTL,	{ .vop_ioctl = ctfs_ev_ioctl } },
    332  3898     rsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = ctfs_ev_getattr } },
    333  3898     rsb 	{ VOPNAME_ACCESS,	{ .vop_access = ctfs_ev_access } },
    334  3898     rsb 	{ VOPNAME_READDIR,	{ .error = fs_notdir } },
    335  3898     rsb 	{ VOPNAME_LOOKUP,	{ .error = fs_notdir } },
    336  3898     rsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = ctfs_ev_inactive } },
    337  3898     rsb 	{ VOPNAME_POLL,		{ .vop_poll = ctfs_ev_poll } },
    338     0  stevel 	{ NULL, NULL }
    339     0  stevel };
    340     0  stevel 
    341     0  stevel /*
    342     0  stevel  * ctfs_create_pbundle
    343     0  stevel  *
    344     0  stevel  * Creates and returns a bunode for a /system/contract/<type>/pbundle
    345     0  stevel  * file.
    346     0  stevel  */
    347     0  stevel vnode_t *
    348     0  stevel ctfs_create_pbundle(vnode_t *pvp)
    349     0  stevel {
    350     0  stevel 	vnode_t *vp;
    351     0  stevel 	ctfs_bunode_t *bundle;
    352     0  stevel 
    353     0  stevel 	vp = gfs_file_create(sizeof (ctfs_bunode_t), pvp, ctfs_ops_bundle);
    354     0  stevel 	bundle = vp->v_data;
    355     0  stevel 	bundle->ctfs_bu_queue =
    356     0  stevel 	    contract_type_pbundle(ct_types[gfs_file_index(pvp)], curproc);
    357     0  stevel 
    358     0  stevel 	return (vp);
    359     0  stevel }
    360     0  stevel 
    361     0  stevel /*
    362     0  stevel  * ctfs_create_bundle
    363     0  stevel  *
    364     0  stevel  * Creates and returns a bunode for a /system/contract/<type>/bundle
    365     0  stevel  * file.
    366     0  stevel  */
    367     0  stevel vnode_t *
    368     0  stevel ctfs_create_bundle(vnode_t *pvp)
    369     0  stevel {
    370     0  stevel 	vnode_t *vp;
    371     0  stevel 	ctfs_bunode_t *bundle;
    372     0  stevel 
    373     0  stevel 	vp = gfs_file_create(sizeof (ctfs_bunode_t), pvp, ctfs_ops_bundle);
    374     0  stevel 	bundle = vp->v_data;
    375     0  stevel 	bundle->ctfs_bu_queue =
    376     0  stevel 	    contract_type_bundle(ct_types[gfs_file_index(pvp)]);
    377     0  stevel 
    378     0  stevel 	return (vp);
    379     0  stevel }
    380     0  stevel 
    381     0  stevel /*
    382     0  stevel  * ctfs_bu_open - VOP_OPEN entry point
    383     0  stevel  */
    384     0  stevel /* ARGSUSED */
    385     0  stevel static int
    386  5331     amw ctfs_bu_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
    387     0  stevel {
    388     0  stevel 	ctfs_bunode_t *bunode = (*vpp)->v_data;
    389     0  stevel 
    390     0  stevel 	/*
    391     0  stevel 	 * This assumes we are only ever called immediately after a
    392     0  stevel 	 * VOP_LOOKUP.  We could clone ourselves here, but doing so
    393     0  stevel 	 * would make /proc/pid/fd accesses less useful.
    394     0  stevel 	 */
    395     0  stevel 	return (ctfs_endpoint_open(&bunode->ctfs_bu_listener,
    396     0  stevel 	    bunode->ctfs_bu_queue, flag));
    397     0  stevel }
    398     0  stevel 
    399     0  stevel /*
    400     0  stevel  * ctfs_bu_inactive - VOP_INACTIVE entry point
    401     0  stevel  */
    402     0  stevel /* ARGSUSED */
    403     0  stevel static void
    404  5331     amw ctfs_bu_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
    405     0  stevel {
    406     0  stevel 	ctfs_bunode_t *bunode;
    407     0  stevel 	vnode_t *pvp = gfs_file_parent(vp);
    408     0  stevel 
    409     0  stevel 	/*
    410     0  stevel 	 * See comments in ctfs_ev_inactive() above.
    411     0  stevel 	 */
    412     0  stevel 	VN_HOLD(pvp);
    413     0  stevel 	if ((bunode = gfs_file_inactive(vp)) != NULL) {
    414     0  stevel 		ctfs_endpoint_inactive(&bunode->ctfs_bu_listener);
    415     0  stevel 		kmem_free(bunode, sizeof (ctfs_bunode_t));
    416     0  stevel 	}
    417     0  stevel 	VN_RELE(pvp);
    418     0  stevel }
    419     0  stevel 
    420     0  stevel /*
    421     0  stevel  * ctfs_bu_getattr - VOP_GETATTR entry point
    422     0  stevel  */
    423     0  stevel /* ARGSUSED */
    424     0  stevel static int
    425  5331     amw ctfs_bu_getattr(
    426  5331     amw 	vnode_t *vp,
    427  5331     amw 	vattr_t *vap,
    428  5331     amw 	int flags,
    429  5331     amw 	cred_t *cr,
    430  5331     amw 	caller_context_t *ct)
    431     0  stevel {
    432     0  stevel 	ctfs_bunode_t *bunode = vp->v_data;
    433     0  stevel 
    434     0  stevel 	vap->va_type = VREG;
    435     0  stevel 	vap->va_mode = 0444;
    436     0  stevel 	vap->va_nodeid = gfs_file_index(vp);
    437     0  stevel 	vap->va_nlink = 1;
    438     0  stevel 	vap->va_size = 0;
    439     0  stevel 	vap->va_ctime.tv_sec = vp->v_vfsp->vfs_mtime;
    440     0  stevel 	vap->va_ctime.tv_nsec = 0;
    441     0  stevel 	mutex_enter(&bunode->ctfs_bu_queue->ctq_lock);
    442     0  stevel 	vap->va_mtime = vap->va_atime = bunode->ctfs_bu_queue->ctq_atime;
    443     0  stevel 	mutex_exit(&bunode->ctfs_bu_queue->ctq_lock);
    444     0  stevel 	ctfs_common_getattr(vp, vap);
    445     0  stevel 
    446     0  stevel 	return (0);
    447     0  stevel }
    448     0  stevel 
    449     0  stevel /*
    450     0  stevel  * ctfs_bu_ioctl - VOP_IOCTL entry point
    451     0  stevel  */
    452     0  stevel /* ARGSUSED */
    453     0  stevel static int
    454  5331     amw ctfs_bu_ioctl(
    455  5331     amw 	vnode_t *vp,
    456  5331     amw 	int cmd,
    457  5331     amw 	intptr_t arg,
    458  5331     amw 	int flag,
    459  5331     amw 	cred_t *cr,
    460  5331     amw 	int *rvalp,
    461  5331     amw 	caller_context_t *ct)
    462     0  stevel {
    463     0  stevel 	ctfs_bunode_t *bunode = vp->v_data;
    464     0  stevel 
    465     0  stevel 	return (ctfs_endpoint_ioctl(&bunode->ctfs_bu_listener, cmd, arg, cr,
    466   789  ahrens 	    VTOZONE(vp), bunode->ctfs_bu_queue->ctq_listno == CTEL_BUNDLE));
    467     0  stevel }
    468     0  stevel 
    469     0  stevel /*
    470     0  stevel  * ctfs_bu_poll - VOP_POLL entry point
    471     0  stevel  */
    472  5331     amw /*ARGSUSED*/
    473     0  stevel static int
    474  5331     amw ctfs_bu_poll(
    475  5331     amw 	vnode_t *vp,
    476  5331     amw 	short events,
    477  5331     amw 	int anyyet,
    478  5331     amw 	short *reventsp,
    479  5331     amw 	pollhead_t **php,
    480  5331     amw 	caller_context_t *ct)
    481     0  stevel {
    482     0  stevel 	ctfs_bunode_t *bunode = vp->v_data;
    483     0  stevel 
    484     0  stevel 	return (ctfs_endpoint_poll(&bunode->ctfs_bu_listener, events, anyyet,
    485     0  stevel 	    reventsp, php));
    486     0  stevel }
    487     0  stevel 
    488     0  stevel const fs_operation_def_t ctfs_tops_bundle[] = {
    489  3898     rsb 	{ VOPNAME_OPEN,		{ .vop_open = ctfs_bu_open } },
    490  3898     rsb 	{ VOPNAME_CLOSE,	{ .vop_close = ctfs_close } },
    491  3898     rsb 	{ VOPNAME_IOCTL,	{ .vop_ioctl = ctfs_bu_ioctl } },
    492  3898     rsb 	{ VOPNAME_GETATTR,	{ .vop_getattr = ctfs_bu_getattr } },
    493  3898     rsb 	{ VOPNAME_ACCESS,	{ .vop_access = ctfs_access_readonly } },
    494  3898     rsb 	{ VOPNAME_READDIR,	{ .error = fs_notdir } },
    495  3898     rsb 	{ VOPNAME_LOOKUP,	{ .error = fs_notdir } },
    496  3898     rsb 	{ VOPNAME_INACTIVE,	{ .vop_inactive = ctfs_bu_inactive } },
    497  3898     rsb 	{ VOPNAME_POLL,		{ .vop_poll = ctfs_bu_poll } },
    498     0  stevel 	{ NULL, NULL }
    499     0  stevel };
    500