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 46 0 stevel /* 47 0 stevel * CTFS routines for the /system/contract/<type>/<ctid>/ctl vnode. 48 0 stevel * CTFS routines for the /system/contract/<type>/<ctid>/status vnode. 49 0 stevel */ 50 0 stevel 51 0 stevel /* 52 0 stevel * ctfs_create_ctlnode 53 0 stevel * 54 0 stevel * If necessary, creates a ctlnode for a ctl file and inserts it into 55 0 stevel * the specified cdirnode's gfs_dir_t. Returns either the existing 56 0 stevel * vnode or the new one. 57 0 stevel */ 58 0 stevel vnode_t * 59 0 stevel ctfs_create_ctlnode(vnode_t *pvp) 60 0 stevel { 61 0 stevel ctfs_ctlnode_t *ctlnode; 62 0 stevel ctfs_cdirnode_t *cdirnode = pvp->v_data; 63 0 stevel vnode_t *vp; 64 0 stevel 65 0 stevel vp = gfs_file_create(sizeof (ctfs_ctlnode_t), pvp, ctfs_ops_ctl); 66 0 stevel ctlnode = vp->v_data; 67 0 stevel /* 68 0 stevel * We transitively have a hold on the contract through our 69 0 stevel * parent directory. 70 0 stevel */ 71 0 stevel ctlnode->ctfs_ctl_contract = cdirnode->ctfs_cn_contract; 72 0 stevel 73 0 stevel return (vp); 74 0 stevel } 75 0 stevel 76 0 stevel /* 77 0 stevel * ctfs_ctl_access - VOP_ACCESS entry point 78 0 stevel * 79 0 stevel * You only get to access ctl files for contracts you own or were 80 0 stevel * abandoned and inherited by your containing process contract. 81 0 stevel */ 82 0 stevel /* ARGSUSED */ 83 0 stevel static int 84 5331 amw ctfs_ctl_access( 85 5331 amw vnode_t *vp, 86 5331 amw int mode, 87 5331 amw int flags, 88 5331 amw cred_t *cr, 89 5331 amw caller_context_t *cct) 90 0 stevel { 91 0 stevel ctfs_ctlnode_t *ctlnode = vp->v_data; 92 0 stevel contract_t *ct = ctlnode->ctfs_ctl_contract; 93 0 stevel 94 0 stevel if (mode & (VEXEC | VREAD)) 95 0 stevel return (EACCES); 96 0 stevel 97 0 stevel mutex_enter(&ct->ct_lock); 98 0 stevel if ((curproc == ct->ct_owner) || 99 0 stevel (ct->ct_owner == NULL && ct->ct_regent != NULL && 100 0 stevel ct->ct_regent->ct_data == curproc->p_ct_process)) { 101 0 stevel mutex_exit(&ct->ct_lock); 102 0 stevel return (0); 103 0 stevel } 104 0 stevel 105 0 stevel mutex_exit(&ct->ct_lock); 106 0 stevel return (EACCES); 107 0 stevel } 108 0 stevel 109 0 stevel /* 110 0 stevel * ctfs_ctl_open - VOP_OPEN entry point 111 0 stevel * 112 0 stevel * Just checks to make sure the mode bits are set, and that the 113 0 stevel * constraints imposed by ctfs_ctl_access are met. 114 0 stevel */ 115 0 stevel static int 116 5331 amw ctfs_ctl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 117 0 stevel { 118 0 stevel if (flag != (FWRITE | FOFFMAX)) 119 0 stevel return (EINVAL); 120 0 stevel 121 5331 amw return (ctfs_ctl_access(*vpp, VWRITE, 0, cr, ct)); 122 0 stevel } 123 0 stevel 124 0 stevel /* 125 4340 acruz * ctfs_ctl_common_getattr 126 5331 amw * Implements functionality common to ctl and status ctfs VOP_GETATTR 127 4340 acruz * entry points. It assumes vp->v_data is set 128 0 stevel */ 129 0 stevel static int 130 4347 acruz ctfs_ctl_common_getattr(vnode_t *vp, vattr_t *vap) 131 0 stevel { 132 0 stevel ctfs_ctlnode_t *ctlnode = vp->v_data; 133 0 stevel 134 0 stevel vap->va_type = VREG; 135 0 stevel vap->va_nlink = 1; 136 0 stevel vap->va_size = 0; 137 0 stevel vap->va_ctime = ctlnode->ctfs_ctl_contract->ct_ctime; 138 0 stevel mutex_enter(&ctlnode->ctfs_ctl_contract->ct_events.ctq_lock); 139 0 stevel vap->va_atime = vap->va_mtime = 140 0 stevel ctlnode->ctfs_ctl_contract->ct_events.ctq_atime; 141 0 stevel mutex_exit(&ctlnode->ctfs_ctl_contract->ct_events.ctq_lock); 142 0 stevel ctfs_common_getattr(vp, vap); 143 0 stevel 144 0 stevel return (0); 145 4340 acruz } 146 4340 acruz 147 4340 acruz /* 148 4340 acruz * ctfs_ctl_getattr - VOP_GETATTR entry point 149 4340 acruz */ 150 4340 acruz /* ARGSUSED */ 151 4340 acruz static int 152 5331 amw ctfs_ctl_getattr(vnode_t *vp, vattr_t *vap, int flags, 153 5331 amw cred_t *cr, caller_context_t *ct) 154 4340 acruz { 155 4340 acruz vap->va_mode = 0222; 156 4340 acruz 157 4347 acruz return (ctfs_ctl_common_getattr(vp, vap)); 158 4340 acruz } 159 4340 acruz 160 4340 acruz /* 161 4340 acruz * ctfs_stat_getattr - VOP_GETATTR entry point 162 4340 acruz */ 163 4340 acruz /* ARGSUSED */ 164 4340 acruz static int 165 5331 amw ctfs_stat_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 166 5331 amw caller_context_t *ct) 167 4340 acruz { 168 4340 acruz vap->va_mode = 0444; 169 4340 acruz 170 4347 acruz return (ctfs_ctl_common_getattr(vp, vap)); 171 0 stevel } 172 0 stevel 173 0 stevel /* 174 0 stevel * ctfs_ctl_ioctl - VOP_IOCTL entry point 175 0 stevel * 176 0 stevel * All the ct_ctl_*(3contract) interfaces point here. 177 0 stevel */ 178 0 stevel /* ARGSUSED */ 179 0 stevel static int 180 5331 amw ctfs_ctl_ioctl( 181 5331 amw vnode_t *vp, 182 5331 amw int cmd, 183 5331 amw intptr_t arg, 184 5331 amw int flag, 185 5331 amw cred_t *cr, 186 5331 amw int *rvalp, 187 5331 amw caller_context_t *cct) 188 0 stevel { 189 0 stevel ctfs_ctlnode_t *ctlnode = vp->v_data; 190 0 stevel contract_t *ct = ctlnode->ctfs_ctl_contract; 191 0 stevel int error = 0; 192 0 stevel uint64_t event; 193 4845 vikram int ack; 194 0 stevel 195 0 stevel switch (cmd) { 196 0 stevel case CT_CABANDON: 197 0 stevel error = contract_abandon(ct, curproc, 1); 198 0 stevel break; 199 0 stevel 200 0 stevel case CT_CACK: 201 4845 vikram case CT_CNACK: 202 0 stevel if (copyin((void *)arg, &event, sizeof (uint64_t))) 203 0 stevel return (EFAULT); 204 4845 vikram ack = (cmd == CT_CACK) ? CT_ACK : CT_NACK; 205 4845 vikram error = contract_ack(ct, event, ack); 206 0 stevel break; 207 0 stevel 208 0 stevel case CT_CNEWCT: 209 4845 vikram error = contract_newct(ct); 210 0 stevel break; 211 0 stevel 212 0 stevel case CT_CQREQ: 213 4845 vikram if (copyin((void *)arg, &event, sizeof (uint64_t))) 214 4845 vikram return (EFAULT); 215 4845 vikram error = contract_qack(ct, event); 216 0 stevel break; 217 0 stevel 218 0 stevel case CT_CADOPT: 219 0 stevel error = contract_adopt(ct, curproc); 220 0 stevel break; 221 0 stevel 222 0 stevel default: 223 0 stevel return (EINVAL); 224 0 stevel } 225 0 stevel 226 0 stevel return (error); 227 0 stevel } 228 0 stevel 229 0 stevel const fs_operation_def_t ctfs_tops_ctl[] = { 230 3898 rsb { VOPNAME_OPEN, { .vop_open = ctfs_ctl_open } }, 231 3898 rsb { VOPNAME_CLOSE, { .vop_close = ctfs_close } }, 232 3898 rsb { VOPNAME_IOCTL, { .vop_ioctl = ctfs_ctl_ioctl } }, 233 3898 rsb { VOPNAME_GETATTR, { .vop_getattr = ctfs_ctl_getattr } }, 234 3898 rsb { VOPNAME_ACCESS, { .vop_access = ctfs_ctl_access } }, 235 3898 rsb { VOPNAME_READDIR, { .error = fs_notdir } }, 236 3898 rsb { VOPNAME_LOOKUP, { .error = fs_notdir } }, 237 3898 rsb { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 238 0 stevel { NULL, NULL } 239 0 stevel }; 240 0 stevel 241 0 stevel /* 242 0 stevel * ctfs_create_statnode 243 0 stevel * 244 0 stevel * If necessary, creates a ctlnode for a status file and inserts it 245 0 stevel * into the specified cdirnode's gfs_dir_t. Returns either the 246 0 stevel * existing vnode or the new one. 247 0 stevel */ 248 0 stevel vnode_t * 249 0 stevel ctfs_create_statnode(vnode_t *pvp) 250 0 stevel { 251 0 stevel vnode_t *vp; 252 0 stevel ctfs_cdirnode_t *cdirnode = pvp->v_data; 253 0 stevel ctfs_ctlnode_t *ctlnode; 254 0 stevel 255 0 stevel vp = gfs_file_create(sizeof (ctfs_ctlnode_t), pvp, ctfs_ops_stat); 256 0 stevel ctlnode = vp->v_data; 257 0 stevel /* 258 0 stevel * We transitively have a hold on the contract through our 259 0 stevel * parent directory. 260 0 stevel */ 261 0 stevel ctlnode->ctfs_ctl_contract = cdirnode->ctfs_cn_contract; 262 0 stevel 263 0 stevel return (vp); 264 0 stevel } 265 0 stevel 266 0 stevel /* 267 0 stevel * ctfs_stat_ioctl - VOP_IOCTL entry point 268 0 stevel * 269 0 stevel * The kernel half of ct_status_read(3contract). 270 0 stevel */ 271 0 stevel /* ARGSUSED */ 272 0 stevel static int 273 5331 amw ctfs_stat_ioctl( 274 5331 amw vnode_t *vp, 275 5331 amw int cmd, 276 5331 amw intptr_t arg, 277 5331 amw int flag, 278 5331 amw cred_t *cr, 279 5331 amw int *rvalp, 280 5331 amw caller_context_t *cct) 281 0 stevel { 282 0 stevel ctfs_ctlnode_t *statnode = vp->v_data; 283 0 stevel contract_t *ct = statnode->ctfs_ctl_contract; 284 0 stevel ct_type_t *type = ct->ct_type; 285 0 stevel STRUCT_DECL(ct_status, st); 286 0 stevel nvlist_t *foo; 287 0 stevel char *bufp = NULL; 288 0 stevel size_t len; 289 0 stevel model_t mdl = get_udatamodel(); 290 0 stevel uint_t detail; 291 0 stevel 292 0 stevel STRUCT_INIT(st, mdl); 293 0 stevel 294 0 stevel if (cmd != CT_SSTATUS) 295 0 stevel return (EINVAL); 296 0 stevel 297 0 stevel if (copyin((void *)arg, STRUCT_BUF(st), STRUCT_SIZE(st))) 298 0 stevel return (EFAULT); 299 0 stevel detail = STRUCT_FGET(st, ctst_detail); 300 0 stevel if (detail == CTD_COMMON) { 301 0 stevel mutex_enter(&ct->ct_lock); 302 789 ahrens contract_status_common(ct, VTOZONE(vp), STRUCT_BUF(st), mdl); 303 0 stevel mutex_exit(&ct->ct_lock); 304 0 stevel } else if (detail <= CTD_ALL) { 305 0 stevel VERIFY(nvlist_alloc(&foo, NV_UNIQUE_NAME, KM_SLEEP) == 0); 306 789 ahrens type->ct_type_ops->contop_status(ct, VTOZONE(vp), detail, foo, 307 0 stevel STRUCT_BUF(st), mdl); 308 0 stevel VERIFY(nvlist_pack(foo, &bufp, &len, NV_ENCODE_NATIVE, 309 0 stevel KM_SLEEP) == 0); 310 0 stevel nvlist_free(foo); 311 0 stevel 312 0 stevel if ((len <= STRUCT_FGET(st, ctst_nbytes)) && 313 0 stevel (copyout(bufp, STRUCT_FGETP(st, ctst_buffer), len) == -1)) { 314 0 stevel kmem_free(bufp, len); 315 0 stevel return (EFAULT); 316 0 stevel } 317 0 stevel kmem_free(bufp, len); 318 0 stevel STRUCT_FSET(st, ctst_nbytes, len); 319 0 stevel } else { 320 0 stevel return (EINVAL); 321 0 stevel } 322 0 stevel if (copyout(STRUCT_BUF(st), (void *)arg, STRUCT_SIZE(st))) 323 0 stevel return (EFAULT); 324 0 stevel 325 0 stevel return (0); 326 0 stevel } 327 0 stevel 328 0 stevel const fs_operation_def_t ctfs_tops_stat[] = { 329 3898 rsb { VOPNAME_OPEN, { .vop_open = ctfs_open } }, 330 3898 rsb { VOPNAME_CLOSE, { .vop_close = ctfs_close } }, 331 3898 rsb { VOPNAME_IOCTL, { .vop_ioctl = ctfs_stat_ioctl } }, 332 4340 acruz { VOPNAME_GETATTR, { .vop_getattr = ctfs_stat_getattr } }, 333 3898 rsb { VOPNAME_ACCESS, { .vop_access = ctfs_access_readonly } }, 334 3898 rsb { VOPNAME_READDIR, { .error = fs_notdir } }, 335 3898 rsb { VOPNAME_LOOKUP, { .error = fs_notdir } }, 336 3898 rsb { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 337 0 stevel { NULL, NULL } 338 0 stevel }; 339