4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/types.h>
29 #include <sys/param.h>
34 #include <sys/vnode.h>
35 #include <sys/systm.h>
36 #include <sys/errno.h>
37 #include <sys/sysmacros.h>
38 #include <sys/fs_subr.h>
39 #include <sys/contract.h>
40 #include <sys/contract_impl.h>
42 #include <sys/ctfs_impl.h>
46 * CTFS routines for the /system/contract/<type>/<ctid>/ctl vnode.
47 * CTFS routines for the /system/contract/<type>/<ctid>/status vnode.
53 * If necessary, creates a ctlnode for a ctl file and inserts it into
54 * the specified cdirnode's gfs_dir_t. Returns either the existing
55 * vnode or the new one.
58 ctfs_create_ctlnode(vnode_t
*pvp
)
60 ctfs_ctlnode_t
*ctlnode
;
61 ctfs_cdirnode_t
*cdirnode
= pvp
->v_data
;
64 vp
= gfs_file_create(sizeof (ctfs_ctlnode_t
), pvp
, &ctfs_ops_ctl
);
67 * We transitively have a hold on the contract through our
70 ctlnode
->ctfs_ctl_contract
= cdirnode
->ctfs_cn_contract
;
76 * ctfs_ctl_access - fop_access entry point
78 * You only get to access ctl files for contracts you own or were
79 * abandoned and inherited by your containing process contract.
88 caller_context_t
*cct
)
90 ctfs_ctlnode_t
*ctlnode
= vp
->v_data
;
91 contract_t
*ct
= ctlnode
->ctfs_ctl_contract
;
93 if (mode
& (VEXEC
| VREAD
))
96 mutex_enter(&ct
->ct_lock
);
97 if ((curproc
== ct
->ct_owner
) ||
98 (ct
->ct_owner
== NULL
&& ct
->ct_regent
!= NULL
&&
99 ct
->ct_regent
->ct_data
== curproc
->p_ct_process
)) {
100 mutex_exit(&ct
->ct_lock
);
104 mutex_exit(&ct
->ct_lock
);
109 * ctfs_ctl_open - fop_open entry point
111 * Just checks to make sure the mode bits are set, and that the
112 * constraints imposed by ctfs_ctl_access are met.
115 ctfs_ctl_open(vnode_t
**vpp
, int flag
, cred_t
*cr
, caller_context_t
*ct
)
117 if (flag
!= (FWRITE
| FOFFMAX
))
120 return (ctfs_ctl_access(*vpp
, VWRITE
, 0, cr
, ct
));
124 * ctfs_ctl_common_getattr
125 * Implements functionality common to ctl and status ctfs fop_getattr
126 * entry points. It assumes vp->v_data is set
129 ctfs_ctl_common_getattr(vnode_t
*vp
, vattr_t
*vap
)
131 ctfs_ctlnode_t
*ctlnode
= vp
->v_data
;
136 vap
->va_ctime
= ctlnode
->ctfs_ctl_contract
->ct_ctime
;
137 mutex_enter(&ctlnode
->ctfs_ctl_contract
->ct_events
.ctq_lock
);
138 vap
->va_atime
= vap
->va_mtime
=
139 ctlnode
->ctfs_ctl_contract
->ct_events
.ctq_atime
;
140 mutex_exit(&ctlnode
->ctfs_ctl_contract
->ct_events
.ctq_lock
);
141 ctfs_common_getattr(vp
, vap
);
147 * ctfs_ctl_getattr - fop_getattr entry point
151 ctfs_ctl_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
,
152 cred_t
*cr
, caller_context_t
*ct
)
156 return (ctfs_ctl_common_getattr(vp
, vap
));
160 * ctfs_stat_getattr - fop_getattr entry point
164 ctfs_stat_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
165 caller_context_t
*ct
)
169 return (ctfs_ctl_common_getattr(vp
, vap
));
173 * ctfs_ctl_ioctl - fop_ioctl entry point
175 * All the ct_ctl_*(3contract) interfaces point here.
186 caller_context_t
*cct
)
188 ctfs_ctlnode_t
*ctlnode
= vp
->v_data
;
189 contract_t
*ct
= ctlnode
->ctfs_ctl_contract
;
196 error
= contract_abandon(ct
, curproc
, 1);
201 if (copyin((void *)arg
, &event
, sizeof (uint64_t)))
203 ack
= (cmd
== CT_CACK
) ? CT_ACK
: CT_NACK
;
204 error
= contract_ack(ct
, event
, ack
);
208 error
= contract_newct(ct
);
212 if (copyin((void *)arg
, &event
, sizeof (uint64_t)))
214 error
= contract_qack(ct
, event
);
218 error
= contract_adopt(ct
, curproc
);
228 const struct vnodeops ctfs_ops_ctl
= {
229 .vnop_name
= "ctfs ctl file",
230 .vop_open
= ctfs_ctl_open
,
231 .vop_close
= ctfs_close
,
232 .vop_ioctl
= ctfs_ctl_ioctl
,
233 .vop_getattr
= ctfs_ctl_getattr
,
234 .vop_access
= ctfs_ctl_access
,
235 .vop_readdir
= fs_notdir
,
236 .vop_lookup
= fs_notdir
,
237 .vop_inactive
= gfs_vop_inactive
,
241 * ctfs_create_statnode
243 * If necessary, creates a ctlnode for a status file and inserts it
244 * into the specified cdirnode's gfs_dir_t. Returns either the
245 * existing vnode or the new one.
248 ctfs_create_statnode(vnode_t
*pvp
)
251 ctfs_cdirnode_t
*cdirnode
= pvp
->v_data
;
252 ctfs_ctlnode_t
*ctlnode
;
254 vp
= gfs_file_create(sizeof (ctfs_ctlnode_t
), pvp
, &ctfs_ops_stat
);
255 ctlnode
= vp
->v_data
;
257 * We transitively have a hold on the contract through our
260 ctlnode
->ctfs_ctl_contract
= cdirnode
->ctfs_cn_contract
;
266 * ctfs_stat_ioctl - fop_ioctl entry point
268 * The kernel half of ct_status_read(3contract).
279 caller_context_t
*cct
)
281 ctfs_ctlnode_t
*statnode
= vp
->v_data
;
282 contract_t
*ct
= statnode
->ctfs_ctl_contract
;
283 ct_type_t
*type
= ct
->ct_type
;
284 STRUCT_DECL(ct_status
, st
);
288 model_t mdl
= get_udatamodel();
291 STRUCT_INIT(st
, mdl
);
293 if (cmd
!= CT_SSTATUS
)
296 if (copyin((void *)arg
, STRUCT_BUF(st
), STRUCT_SIZE(st
)))
298 detail
= STRUCT_FGET(st
, ctst_detail
);
299 if (detail
== CTD_COMMON
) {
300 mutex_enter(&ct
->ct_lock
);
301 contract_status_common(ct
, VTOZONE(vp
), STRUCT_BUF(st
), mdl
);
302 mutex_exit(&ct
->ct_lock
);
303 } else if (detail
<= CTD_ALL
) {
304 VERIFY(nvlist_alloc(&foo
, NV_UNIQUE_NAME
, KM_SLEEP
) == 0);
305 type
->ct_type_ops
->contop_status(ct
, VTOZONE(vp
), detail
, foo
,
306 STRUCT_BUF(st
), mdl
);
307 VERIFY(nvlist_pack(foo
, &bufp
, &len
, NV_ENCODE_NATIVE
,
311 if ((len
<= STRUCT_FGET(st
, ctst_nbytes
)) &&
312 (copyout(bufp
, STRUCT_FGETP(st
, ctst_buffer
), len
) == -1)) {
313 kmem_free(bufp
, len
);
316 kmem_free(bufp
, len
);
317 STRUCT_FSET(st
, ctst_nbytes
, len
);
321 if (copyout(STRUCT_BUF(st
), (void *)arg
, STRUCT_SIZE(st
)))
327 const struct vnodeops ctfs_ops_stat
= {
328 .vnop_name
= "ctfs status file",
329 .vop_open
= ctfs_open
,
330 .vop_close
= ctfs_close
,
331 .vop_ioctl
= ctfs_stat_ioctl
,
332 .vop_getattr
= ctfs_stat_getattr
,
333 .vop_access
= ctfs_access_readonly
,
334 .vop_readdir
= fs_notdir
,
335 .vop_lookup
= fs_notdir
,
336 .vop_inactive
= gfs_vop_inactive
,