1 1.38 dholland /* $NetBSD: puffs_node.c,v 1.38 2018/02/08 09:05:20 dholland Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Development of this software was supported by the 7 1.1 pooka * Google Summer of Code program, the Ulla Tuominen Foundation 8 1.1 pooka * and the Finnish Cultural Foundation. 9 1.1 pooka * 10 1.1 pooka * Redistribution and use in source and binary forms, with or without 11 1.1 pooka * modification, are permitted provided that the following conditions 12 1.1 pooka * are met: 13 1.1 pooka * 1. Redistributions of source code must retain the above copyright 14 1.1 pooka * notice, this list of conditions and the following disclaimer. 15 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 pooka * notice, this list of conditions and the following disclaimer in the 17 1.1 pooka * documentation and/or other materials provided with the distribution. 18 1.1 pooka * 19 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 pooka * SUCH DAMAGE. 30 1.1 pooka */ 31 1.1 pooka 32 1.1 pooka #include <sys/cdefs.h> 33 1.38 dholland __KERNEL_RCSID(0, "$NetBSD: puffs_node.c,v 1.38 2018/02/08 09:05:20 dholland Exp $"); 34 1.1 pooka 35 1.1 pooka #include <sys/param.h> 36 1.1 pooka #include <sys/hash.h> 37 1.1 pooka #include <sys/kmem.h> 38 1.1 pooka #include <sys/mount.h> 39 1.1 pooka #include <sys/namei.h> 40 1.1 pooka #include <sys/vnode.h> 41 1.1 pooka 42 1.21 manu #include <uvm/uvm.h> 43 1.21 manu 44 1.1 pooka #include <fs/puffs/puffs_msgif.h> 45 1.1 pooka #include <fs/puffs/puffs_sys.h> 46 1.1 pooka 47 1.1 pooka #include <miscfs/genfs/genfs_node.h> 48 1.1 pooka #include <miscfs/specfs/specdev.h> 49 1.1 pooka 50 1.1 pooka struct pool puffs_pnpool; 51 1.24 manu struct pool puffs_vapool; 52 1.1 pooka 53 1.1 pooka /* 54 1.38 dholland * Grab a vnode, initialize all the puffs-dependent stuff. 55 1.1 pooka */ 56 1.32 hannken static int 57 1.32 hannken puffs_getvnode1(struct mount *mp, puffs_cookie_t ck, enum vtype type, 58 1.32 hannken voff_t vsize, dev_t rdev, bool may_exist, struct vnode **vpp) 59 1.1 pooka { 60 1.1 pooka struct puffs_mount *pmp; 61 1.10 ad struct vnode *vp; 62 1.1 pooka struct puffs_node *pnode; 63 1.1 pooka int error; 64 1.1 pooka 65 1.1 pooka pmp = MPTOPUFFSMP(mp); 66 1.1 pooka 67 1.3 pooka if (type <= VNON || type >= VBAD) { 68 1.7 pooka puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL, 69 1.11 pooka "bad node type", ck); 70 1.32 hannken return EPROTO; 71 1.3 pooka } 72 1.3 pooka if (vsize == VSIZENOTSET) { 73 1.7 pooka puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EINVAL, 74 1.11 pooka "VSIZENOTSET is not a valid size", ck); 75 1.32 hannken return EPROTO; 76 1.1 pooka } 77 1.1 pooka 78 1.32 hannken for (;;) { 79 1.32 hannken error = vcache_get(mp, &ck, sizeof(ck), &vp); 80 1.32 hannken if (error) 81 1.32 hannken return error; 82 1.32 hannken mutex_enter(vp->v_interlock); 83 1.32 hannken pnode = VPTOPP(vp); 84 1.32 hannken if (pnode != NULL) 85 1.32 hannken break; 86 1.32 hannken mutex_exit(vp->v_interlock); 87 1.32 hannken vrele(vp); 88 1.18 rmind } 89 1.32 hannken mutex_enter(&pnode->pn_mtx); 90 1.32 hannken mutex_exit(vp->v_interlock); 91 1.1 pooka 92 1.1 pooka /* 93 1.32 hannken * Release and error out if caller wants a fresh vnode. 94 1.4 pooka */ 95 1.32 hannken if (vp->v_type != VNON && ! may_exist) { 96 1.32 hannken mutex_exit(&pnode->pn_mtx); 97 1.32 hannken vrele(vp); 98 1.32 hannken return EEXIST; 99 1.32 hannken } 100 1.4 pooka 101 1.32 hannken *vpp = vp; 102 1.1 pooka 103 1.32 hannken /* 104 1.32 hannken * If fully initialized were done. 105 1.32 hannken */ 106 1.32 hannken if (vp->v_type != VNON) { 107 1.32 hannken mutex_exit(&pnode->pn_mtx); 108 1.32 hannken return 0; 109 1.32 hannken } 110 1.32 hannken 111 1.32 hannken /* 112 1.32 hannken * Set type and finalize the initialisation. 113 1.32 hannken */ 114 1.32 hannken vp->v_type = type; 115 1.32 hannken if (type == VCHR || type == VBLK) { 116 1.1 pooka vp->v_op = puffs_specop_p; 117 1.10 ad spec_node_init(vp, rdev); 118 1.32 hannken } else if (type == VFIFO) { 119 1.1 pooka vp->v_op = puffs_fifoop_p; 120 1.32 hannken } else if (vp->v_type == VREG) { 121 1.1 pooka uvm_vnp_setsize(vp, vsize); 122 1.1 pooka } 123 1.1 pooka 124 1.1 pooka pnode->pn_serversize = vsize; 125 1.1 pooka 126 1.1 pooka DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp, 127 1.1 pooka pnode, pnode->pn_cookie)); 128 1.1 pooka 129 1.32 hannken mutex_exit(&pnode->pn_mtx); 130 1.32 hannken 131 1.1 pooka return 0; 132 1.32 hannken } 133 1.1 pooka 134 1.32 hannken int 135 1.32 hannken puffs_getvnode(struct mount *mp, puffs_cookie_t ck, enum vtype type, 136 1.32 hannken voff_t vsize, dev_t rdev, struct vnode **vpp) 137 1.32 hannken { 138 1.1 pooka 139 1.32 hannken return puffs_getvnode1(mp, ck, type, vsize, rdev, true, vpp); 140 1.1 pooka } 141 1.1 pooka 142 1.1 pooka /* new node creating for creative vop ops (create, symlink, mkdir, mknod) */ 143 1.1 pooka int 144 1.1 pooka puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp, 145 1.11 pooka puffs_cookie_t ck, struct componentname *cnp, 146 1.11 pooka enum vtype type, dev_t rdev) 147 1.1 pooka { 148 1.1 pooka struct puffs_mount *pmp = MPTOPUFFSMP(mp); 149 1.1 pooka int error; 150 1.1 pooka 151 1.1 pooka /* userspace probably has this as a NULL op */ 152 1.32 hannken if (ck == NULL) 153 1.32 hannken return EOPNOTSUPP; 154 1.1 pooka 155 1.1 pooka /* 156 1.1 pooka * Check for previous node with the same designation. 157 1.1 pooka * Explicitly check the root node cookie, since it might be 158 1.1 pooka * reclaimed from the kernel when this check is made. 159 1.1 pooka */ 160 1.32 hannken if (ck == pmp->pmp_root_cookie) { 161 1.7 pooka puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST, 162 1.11 pooka "cookie exists", ck); 163 1.1 pooka return EPROTO; 164 1.1 pooka } 165 1.1 pooka 166 1.32 hannken KASSERT(curlwp != uvm.pagedaemon_lwp); 167 1.32 hannken 168 1.32 hannken error = puffs_getvnode1(dvp->v_mount, ck, type, 0, rdev, false, vpp); 169 1.32 hannken if (error) { 170 1.32 hannken if (error == EEXIST) { 171 1.7 pooka puffs_senderr(pmp, PUFFS_ERR_MAKENODE, EEXIST, 172 1.32 hannken "cookie exists", ck); 173 1.32 hannken error = EPROTO; 174 1.1 pooka } 175 1.32 hannken return error; 176 1.1 pooka } 177 1.21 manu 178 1.27 manu if (PUFFS_USE_NAMECACHE(pmp)) 179 1.32 hannken cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, 180 1.28 dholland cnp->cn_flags); 181 1.1 pooka 182 1.33 manu puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0); 183 1.33 manu 184 1.1 pooka return 0; 185 1.1 pooka } 186 1.1 pooka 187 1.1 pooka void 188 1.1 pooka puffs_putvnode(struct vnode *vp) 189 1.1 pooka { 190 1.1 pooka struct puffs_node *pnode; 191 1.1 pooka 192 1.1 pooka pnode = VPTOPP(vp); 193 1.1 pooka 194 1.32 hannken KASSERT(vp->v_tag == VT_PUFFS); 195 1.1 pooka 196 1.1 pooka genfs_node_destroy(vp); 197 1.32 hannken 198 1.32 hannken /* 199 1.32 hannken * To interlock with puffs_getvnode1(). 200 1.32 hannken */ 201 1.32 hannken mutex_enter(vp->v_interlock); 202 1.32 hannken vp->v_data = NULL; 203 1.32 hannken mutex_exit(vp->v_interlock); 204 1.1 pooka puffs_releasenode(pnode); 205 1.1 pooka } 206 1.1 pooka 207 1.1 pooka /* 208 1.1 pooka * Make sure root vnode exists and reference it. Does NOT lock. 209 1.1 pooka */ 210 1.1 pooka static int 211 1.1 pooka puffs_makeroot(struct puffs_mount *pmp) 212 1.1 pooka { 213 1.1 pooka struct vnode *vp; 214 1.1 pooka int rv; 215 1.1 pooka 216 1.1 pooka /* 217 1.1 pooka * pmp_lock must be held if vref()'ing or vrele()'ing the 218 1.1 pooka * root vnode. the latter is controlled by puffs_inactive(). 219 1.1 pooka * 220 1.1 pooka * pmp_root is set here and cleared in puffs_reclaim(). 221 1.1 pooka */ 222 1.1 pooka 223 1.32 hannken rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie, 224 1.32 hannken pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp); 225 1.32 hannken if (rv != 0) 226 1.1 pooka return rv; 227 1.1 pooka 228 1.1 pooka mutex_enter(&pmp->pmp_lock); 229 1.32 hannken if (pmp->pmp_root == NULL) 230 1.32 hannken pmp->pmp_root = vp; 231 1.1 pooka mutex_exit(&pmp->pmp_lock); 232 1.1 pooka 233 1.1 pooka return 0; 234 1.1 pooka } 235 1.1 pooka 236 1.1 pooka /* 237 1.1 pooka * Locate the in-kernel vnode based on the cookie received given 238 1.29 yamt * from userspace. 239 1.29 yamt * 240 1.29 yamt * returns 0 on success. otherwise returns an errno or PUFFS_NOSUCHCOOKIE. 241 1.29 yamt * 242 1.29 yamt * returns PUFFS_NOSUCHCOOKIE if no vnode for the cookie is found. 243 1.1 pooka */ 244 1.1 pooka int 245 1.32 hannken puffs_cookie2vnode(struct puffs_mount *pmp, puffs_cookie_t ck, 246 1.32 hannken struct vnode **vpp) 247 1.1 pooka { 248 1.32 hannken int rv; 249 1.1 pooka 250 1.1 pooka /* 251 1.1 pooka * Handle root in a special manner, since we want to make sure 252 1.1 pooka * pmp_root is properly set. 253 1.1 pooka */ 254 1.11 pooka if (ck == pmp->pmp_root_cookie) { 255 1.1 pooka if ((rv = puffs_makeroot(pmp))) 256 1.1 pooka return rv; 257 1.1 pooka *vpp = pmp->pmp_root; 258 1.1 pooka return 0; 259 1.1 pooka } 260 1.1 pooka 261 1.34 hannken rv = vcache_get(PMPTOMP(pmp), &ck, sizeof(ck), vpp); 262 1.32 hannken if (rv != 0) 263 1.32 hannken return rv; 264 1.32 hannken mutex_enter((*vpp)->v_interlock); 265 1.32 hannken if ((*vpp)->v_type == VNON) { 266 1.32 hannken mutex_exit((*vpp)->v_interlock); 267 1.35 manu /* XXX vrele() calls VOP_INACTIVE() with VNON node */ 268 1.32 hannken vrele(*vpp); 269 1.32 hannken *vpp = NULL; 270 1.1 pooka return PUFFS_NOSUCHCOOKIE; 271 1.1 pooka } 272 1.34 hannken mutex_exit((*vpp)->v_interlock); 273 1.1 pooka 274 1.1 pooka return 0; 275 1.1 pooka } 276 1.1 pooka 277 1.1 pooka void 278 1.8 pooka puffs_updatenode(struct puffs_node *pn, int flags, voff_t size) 279 1.1 pooka { 280 1.1 pooka struct timespec ts; 281 1.1 pooka 282 1.1 pooka if (flags == 0) 283 1.1 pooka return; 284 1.1 pooka 285 1.1 pooka nanotime(&ts); 286 1.1 pooka 287 1.1 pooka if (flags & PUFFS_UPDATEATIME) { 288 1.1 pooka pn->pn_mc_atime = ts; 289 1.1 pooka pn->pn_stat |= PNODE_METACACHE_ATIME; 290 1.1 pooka } 291 1.1 pooka if (flags & PUFFS_UPDATECTIME) { 292 1.1 pooka pn->pn_mc_ctime = ts; 293 1.1 pooka pn->pn_stat |= PNODE_METACACHE_CTIME; 294 1.1 pooka } 295 1.1 pooka if (flags & PUFFS_UPDATEMTIME) { 296 1.1 pooka pn->pn_mc_mtime = ts; 297 1.1 pooka pn->pn_stat |= PNODE_METACACHE_MTIME; 298 1.1 pooka } 299 1.1 pooka if (flags & PUFFS_UPDATESIZE) { 300 1.8 pooka pn->pn_mc_size = size; 301 1.1 pooka pn->pn_stat |= PNODE_METACACHE_SIZE; 302 1.1 pooka } 303 1.1 pooka } 304 1.1 pooka 305 1.1 pooka /* 306 1.1 pooka * Add reference to node. 307 1.1 pooka * mutex held on entry and return 308 1.1 pooka */ 309 1.1 pooka void 310 1.1 pooka puffs_referencenode(struct puffs_node *pn) 311 1.1 pooka { 312 1.1 pooka 313 1.1 pooka KASSERT(mutex_owned(&pn->pn_mtx)); 314 1.1 pooka pn->pn_refcount++; 315 1.1 pooka } 316 1.1 pooka 317 1.1 pooka /* 318 1.1 pooka * Release pnode structure which dealing with references to the 319 1.1 pooka * puffs_node instead of the vnode. Can't use vref()/vrele() on 320 1.1 pooka * the vnode there, since that causes the lovely VOP_INACTIVE(), 321 1.1 pooka * which in turn causes the lovely deadlock when called by the one 322 1.1 pooka * who is supposed to handle it. 323 1.1 pooka */ 324 1.1 pooka void 325 1.1 pooka puffs_releasenode(struct puffs_node *pn) 326 1.1 pooka { 327 1.1 pooka 328 1.1 pooka mutex_enter(&pn->pn_mtx); 329 1.1 pooka if (--pn->pn_refcount == 0) { 330 1.1 pooka mutex_exit(&pn->pn_mtx); 331 1.1 pooka mutex_destroy(&pn->pn_mtx); 332 1.20 manu mutex_destroy(&pn->pn_sizemtx); 333 1.12 rmind seldestroy(&pn->pn_sel); 334 1.24 manu if (pn->pn_va_cache != NULL) 335 1.24 manu pool_put(&puffs_vapool, pn->pn_va_cache); 336 1.1 pooka pool_put(&puffs_pnpool, pn); 337 1.1 pooka } else { 338 1.1 pooka mutex_exit(&pn->pn_mtx); 339 1.1 pooka } 340 1.1 pooka } 341