1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/param.h> 28 #include <sys/time.h> 29 #include <sys/cred.h> 30 #include <sys/vfs.h> 31 #include <sys/vfs_opreg.h> 32 #include <sys/gfs.h> 33 #include <sys/vnode.h> 34 #include <sys/systm.h> 35 #include <sys/errno.h> 36 #include <sys/sysmacros.h> 37 #include <fs/fs_subr.h> 38 #include <sys/contract.h> 39 #include <sys/contract_impl.h> 40 #include <sys/ctfs.h> 41 #include <sys/ctfs_impl.h> 42 #include <sys/file.h> 43 44 /* 45 * CTFS routines for the /system/contract/<type>/latest vnode. 46 */ 47 48 /* 49 * ctfs_create_latenode 50 */ 51 vnode_t * 52 ctfs_create_latenode(vnode_t *pvp) 53 { 54 return (gfs_file_create(sizeof (ctfs_latenode_t), pvp, 55 ctfs_ops_latest)); 56 } 57 58 /* 59 * ctfs_latest_nested_open 60 * 61 * The latest node is just a doorway to the status file; this function 62 * is used by ctfs_latest_access, ctfs_latest_open, and 63 * ctfs_latest_getattr to obtain that file. 64 */ 65 static vnode_t * 66 ctfs_latest_nested_open(vnode_t *vp, cred_t *cr) 67 { 68 contract_t *ct = ttolwp(curthread)->lwp_ct_latest[ 69 gfs_file_index(gfs_file_parent(vp))]; 70 71 if (ct) { 72 vnode_t *cvp, *svp; 73 74 cvp = ctfs_create_cdirnode(gfs_file_parent(vp), ct); 75 76 gfs_file_set_index(cvp, -1); 77 78 VERIFY(gfs_dir_lookup(cvp, "status", &svp, 79 cr, 0, NULL, NULL) == 0); 80 81 VN_RELE(cvp); 82 83 return (svp); 84 } 85 86 return (NULL); 87 } 88 89 /* 90 * ctfs_latest_access - VOP_ACCESS entry point 91 * 92 * Fails if there isn't a latest contract. 93 */ 94 /* ARGSUSED */ 95 static int 96 ctfs_latest_access( 97 vnode_t *vp, 98 int mode, 99 int flags, 100 cred_t *cr, 101 caller_context_t *ct) 102 { 103 vnode_t *nvp; 104 105 if (mode & (VEXEC | VWRITE)) 106 return (EACCES); 107 108 if (nvp = ctfs_latest_nested_open(vp, cr)) { 109 VN_RELE(nvp); 110 return (0); 111 } 112 113 return (ESRCH); 114 } 115 116 /* 117 * ctfs_latest_open - VOP_OPEN entry point 118 * 119 * After checking the mode bits, opens and returns the status file for 120 * the LWP's latest contract. 121 */ 122 static int 123 ctfs_latest_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 124 { 125 vnode_t *nvp; 126 127 if (flag != (FREAD | FOFFMAX)) 128 return (EINVAL); 129 130 if (nvp = ctfs_latest_nested_open(*vpp, cr)) { 131 VN_RELE(*vpp); 132 *vpp = nvp; 133 return (VOP_OPEN(vpp, flag, cr, ct)); 134 } 135 136 return (ESRCH); 137 } 138 139 /* 140 * ctfs_latest_getattr - the VOP_GETATTR entry point 141 * 142 * Fetches and calls VOP_GETATTR on the status file for the LWP's 143 * latest contract. Otherwise it fakes up something bland. 144 */ 145 static int 146 ctfs_latest_getattr( 147 vnode_t *vp, 148 vattr_t *vap, 149 int flags, 150 cred_t *cr, 151 caller_context_t *ct) 152 { 153 vnode_t *nvp; 154 155 if (nvp = ctfs_latest_nested_open(vp, cr)) { 156 int res = VOP_GETATTR(nvp, vap, flags, cr, ct); 157 VN_RELE(nvp); 158 return (res); 159 } 160 161 vap->va_type = VREG; 162 vap->va_mode = 0444; 163 vap->va_nlink = 1; 164 vap->va_size = 0; 165 vap->va_ctime.tv_sec = vp->v_vfsp->vfs_mtime; 166 vap->va_ctime.tv_nsec = 0; 167 vap->va_atime = vap->va_mtime = vap->va_ctime; 168 ctfs_common_getattr(vp, vap); 169 170 return (0); 171 } 172 173 const fs_operation_def_t ctfs_tops_latest[] = { 174 { VOPNAME_OPEN, { .vop_open = ctfs_latest_open } }, 175 { VOPNAME_CLOSE, { .error = fs_inval } }, 176 { VOPNAME_IOCTL, { .error = fs_inval } }, 177 { VOPNAME_GETATTR, { .vop_getattr = ctfs_latest_getattr } }, 178 { VOPNAME_ACCESS, { .vop_access = ctfs_latest_access } }, 179 { VOPNAME_READDIR, { .error = fs_notdir } }, 180 { VOPNAME_LOOKUP, { .error = fs_notdir } }, 181 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 182 { NULL, NULL } 183 }; 184