1d167cf6fSWarner Losh /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3d63027b6SPedro F. Giffuni * 4ff7c5a48SPoul-Henning Kamp * Copyright (c) 2000-2004 53f54a085SPoul-Henning Kamp * Poul-Henning Kamp. All rights reserved. 6ff7c5a48SPoul-Henning Kamp * Copyright (c) 1989, 1992-1993, 1995 7ff7c5a48SPoul-Henning Kamp * The Regents of the University of California. All rights reserved. 83f54a085SPoul-Henning Kamp * 93f54a085SPoul-Henning Kamp * This code is derived from software donated to Berkeley by 103f54a085SPoul-Henning Kamp * Jan-Simon Pendry. 113f54a085SPoul-Henning Kamp * 123f54a085SPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 133f54a085SPoul-Henning Kamp * modification, are permitted provided that the following conditions 143f54a085SPoul-Henning Kamp * are met: 153f54a085SPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 163f54a085SPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 173f54a085SPoul-Henning Kamp * 2. Neither the name of the University nor the names of its contributors 183f54a085SPoul-Henning Kamp * may be used to endorse or promote products derived from this software 193f54a085SPoul-Henning Kamp * without specific prior written permission. 203f54a085SPoul-Henning Kamp * 213f54a085SPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 223f54a085SPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 233f54a085SPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 243f54a085SPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 253f54a085SPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 263f54a085SPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 273f54a085SPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 283f54a085SPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 293f54a085SPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 303f54a085SPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313f54a085SPoul-Henning Kamp * SUCH DAMAGE. 323f54a085SPoul-Henning Kamp * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 333f54a085SPoul-Henning Kamp */ 343f54a085SPoul-Henning Kamp 355a9300c4SPoul-Henning Kamp /* 365a9300c4SPoul-Henning Kamp * TODO: 375a9300c4SPoul-Henning Kamp * mkdir: want it ? 385a9300c4SPoul-Henning Kamp */ 395a9300c4SPoul-Henning Kamp 403f54a085SPoul-Henning Kamp #include <sys/param.h> 413f54a085SPoul-Henning Kamp #include <sys/systm.h> 423f54a085SPoul-Henning Kamp #include <sys/conf.h> 43fb919e4dSMark Murray #include <sys/dirent.h> 44e2e050c8SConrad Meyer #include <sys/eventhandler.h> 45ff7c5a48SPoul-Henning Kamp #include <sys/fcntl.h> 4656dd3a61SPoul-Henning Kamp #include <sys/file.h> 4756dd3a61SPoul-Henning Kamp #include <sys/filedesc.h> 4856dd3a61SPoul-Henning Kamp #include <sys/filio.h> 49f8f61460SEd Schouten #include <sys/jail.h> 50fb919e4dSMark Murray #include <sys/kernel.h> 5191898857SMark Johnston #include <sys/limits.h> 52fb919e4dSMark Murray #include <sys/lock.h> 533f54a085SPoul-Henning Kamp #include <sys/malloc.h> 547077c426SJohn Baldwin #include <sys/mman.h> 553f54a085SPoul-Henning Kamp #include <sys/mount.h> 563f54a085SPoul-Henning Kamp #include <sys/namei.h> 57acd3428bSRobert Watson #include <sys/priv.h> 58fb919e4dSMark Murray #include <sys/proc.h> 59ff7c5a48SPoul-Henning Kamp #include <sys/stat.h> 60ff7c5a48SPoul-Henning Kamp #include <sys/sx.h> 614f9343fcSXin LI #include <sys/sysctl.h> 62fb919e4dSMark Murray #include <sys/time.h> 6356dd3a61SPoul-Henning Kamp #include <sys/ttycom.h> 642ab80ed8SDima Dorfman #include <sys/unistd.h> 65fb919e4dSMark Murray #include <sys/vnode.h> 663f54a085SPoul-Henning Kamp 6721806f30SPoul-Henning Kamp static struct vop_vector devfs_vnodeops; 686e572e08SEdward Tomasz Napierala static struct vop_vector devfs_specops; 69*ef9ffb85SMark Johnston static const struct fileops devfs_ops_f; 7021806f30SPoul-Henning Kamp 713f54a085SPoul-Henning Kamp #include <fs/devfs/devfs.h> 72e606a3c6SPoul-Henning Kamp #include <fs/devfs/devfs_int.h> 73e606a3c6SPoul-Henning Kamp 74aed55708SRobert Watson #include <security/mac/mac_framework.h> 75aed55708SRobert Watson 767077c426SJohn Baldwin #include <vm/vm.h> 777077c426SJohn Baldwin #include <vm/vm_extern.h> 787077c426SJohn Baldwin #include <vm/vm_object.h> 797077c426SJohn Baldwin 8082f4d640SKonstantin Belousov static MALLOC_DEFINE(M_CDEVPDATA, "DEVFSP", "Metainfo for cdev-fp data"); 8182f4d640SKonstantin Belousov 82828d6d12SKonstantin Belousov struct mtx devfs_de_interlock; 8356eeb277SStephan Uphoff MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF); 8482f4d640SKonstantin Belousov struct mtx cdevpriv_mtx; 8582f4d640SKonstantin Belousov MTX_SYSINIT(cdevpriv_mtx, &cdevpriv_mtx, "cdevpriv lock", MTX_DEF); 8656eeb277SStephan Uphoff 874f9343fcSXin LI SYSCTL_DECL(_vfs_devfs); 884f9343fcSXin LI 894f9343fcSXin LI static int devfs_dotimes; 904f9343fcSXin LI SYSCTL_INT(_vfs_devfs, OID_AUTO, dotimes, CTLFLAG_RW, 91bda2eb9aSKonstantin Belousov &devfs_dotimes, 0, "Update timestamps on DEVFS with default precision"); 92bda2eb9aSKonstantin Belousov 93bda2eb9aSKonstantin Belousov /* 94bda2eb9aSKonstantin Belousov * Update devfs node timestamp. Note that updates are unlocked and 95bda2eb9aSKonstantin Belousov * stat(2) could see partially updated times. 96bda2eb9aSKonstantin Belousov */ 97bda2eb9aSKonstantin Belousov static void 98bda2eb9aSKonstantin Belousov devfs_timestamp(struct timespec *tsp) 99bda2eb9aSKonstantin Belousov { 100bda2eb9aSKonstantin Belousov time_t ts; 101bda2eb9aSKonstantin Belousov 102bda2eb9aSKonstantin Belousov if (devfs_dotimes) { 103bda2eb9aSKonstantin Belousov vfs_timestamp(tsp); 104bda2eb9aSKonstantin Belousov } else { 105bda2eb9aSKonstantin Belousov ts = time_second; 106bda2eb9aSKonstantin Belousov if (tsp->tv_sec != ts) { 107bda2eb9aSKonstantin Belousov tsp->tv_sec = ts; 108bda2eb9aSKonstantin Belousov tsp->tv_nsec = 0; 109bda2eb9aSKonstantin Belousov } 110bda2eb9aSKonstantin Belousov } 111bda2eb9aSKonstantin Belousov } 1124f9343fcSXin LI 113aac5167cSPoul-Henning Kamp static int 1143979450bSKonstantin Belousov devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp, 1153979450bSKonstantin Belousov int *ref) 116aac5167cSPoul-Henning Kamp { 1173979450bSKonstantin Belousov *dswp = devvn_refthread(fp->f_vnode, devp, ref); 118243b324fSMark Johnston if (*dswp == NULL || *devp != fp->f_data) { 1191663075cSKonstantin Belousov if (*dswp != NULL) 1203979450bSKonstantin Belousov dev_relthread(*devp, *ref); 121aac5167cSPoul-Henning Kamp return (ENXIO); 1221663075cSKonstantin Belousov } 123aac5167cSPoul-Henning Kamp KASSERT((*devp)->si_refcount > 0, 124aac5167cSPoul-Henning Kamp ("devfs: un-referenced struct cdev *(%s)", devtoname(*devp))); 125aac5167cSPoul-Henning Kamp if (*dswp == NULL) 126aac5167cSPoul-Henning Kamp return (ENXIO); 12782f4d640SKonstantin Belousov curthread->td_fpop = fp; 128aac5167cSPoul-Henning Kamp return (0); 129aac5167cSPoul-Henning Kamp } 130aac5167cSPoul-Henning Kamp 13182f4d640SKonstantin Belousov int 13282f4d640SKonstantin Belousov devfs_get_cdevpriv(void **datap) 13382f4d640SKonstantin Belousov { 13482f4d640SKonstantin Belousov struct file *fp; 13582f4d640SKonstantin Belousov struct cdev_privdata *p; 13682f4d640SKonstantin Belousov int error; 13782f4d640SKonstantin Belousov 13882f4d640SKonstantin Belousov fp = curthread->td_fpop; 13982f4d640SKonstantin Belousov if (fp == NULL) 14082f4d640SKonstantin Belousov return (EBADF); 14182f4d640SKonstantin Belousov p = fp->f_cdevpriv; 14282f4d640SKonstantin Belousov if (p != NULL) { 14382f4d640SKonstantin Belousov error = 0; 14482f4d640SKonstantin Belousov *datap = p->cdpd_data; 14582f4d640SKonstantin Belousov } else 14682f4d640SKonstantin Belousov error = ENOENT; 14782f4d640SKonstantin Belousov return (error); 14882f4d640SKonstantin Belousov } 14982f4d640SKonstantin Belousov 15082f4d640SKonstantin Belousov int 1518d7e0f58SJohn Baldwin devfs_set_cdevpriv(void *priv, d_priv_dtor_t *priv_dtr) 15282f4d640SKonstantin Belousov { 15382f4d640SKonstantin Belousov struct file *fp; 15482f4d640SKonstantin Belousov struct cdev_priv *cdp; 15582f4d640SKonstantin Belousov struct cdev_privdata *p; 15682f4d640SKonstantin Belousov int error; 15782f4d640SKonstantin Belousov 15882f4d640SKonstantin Belousov fp = curthread->td_fpop; 15982f4d640SKonstantin Belousov if (fp == NULL) 16082f4d640SKonstantin Belousov return (ENOENT); 16105427aafSKonstantin Belousov cdp = cdev2priv((struct cdev *)fp->f_data); 16282f4d640SKonstantin Belousov p = malloc(sizeof(struct cdev_privdata), M_CDEVPDATA, M_WAITOK); 16382f4d640SKonstantin Belousov p->cdpd_data = priv; 16482f4d640SKonstantin Belousov p->cdpd_dtr = priv_dtr; 16582f4d640SKonstantin Belousov p->cdpd_fp = fp; 16682f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 16782f4d640SKonstantin Belousov if (fp->f_cdevpriv == NULL) { 16882f4d640SKonstantin Belousov LIST_INSERT_HEAD(&cdp->cdp_fdpriv, p, cdpd_list); 16982f4d640SKonstantin Belousov fp->f_cdevpriv = p; 17082f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 17182f4d640SKonstantin Belousov error = 0; 17282f4d640SKonstantin Belousov } else { 17382f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 17482f4d640SKonstantin Belousov free(p, M_CDEVPDATA); 17582f4d640SKonstantin Belousov error = EBUSY; 17682f4d640SKonstantin Belousov } 17782f4d640SKonstantin Belousov return (error); 17882f4d640SKonstantin Belousov } 17982f4d640SKonstantin Belousov 180d3efbe01SKonstantin Belousov int 181d3efbe01SKonstantin Belousov devfs_foreach_cdevpriv(struct cdev *dev, int (*cb)(void *data, void *arg), 182d3efbe01SKonstantin Belousov void *arg) 183d3efbe01SKonstantin Belousov { 184d3efbe01SKonstantin Belousov struct cdev_priv *cdp; 185d3efbe01SKonstantin Belousov struct cdev_privdata *p; 186d3efbe01SKonstantin Belousov int error; 187d3efbe01SKonstantin Belousov 188d3efbe01SKonstantin Belousov cdp = cdev2priv(dev); 189d3efbe01SKonstantin Belousov error = 0; 190d3efbe01SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 191d3efbe01SKonstantin Belousov LIST_FOREACH(p, &cdp->cdp_fdpriv, cdpd_list) { 192d3efbe01SKonstantin Belousov error = cb(p->cdpd_data, arg); 193d3efbe01SKonstantin Belousov if (error != 0) 194d3efbe01SKonstantin Belousov break; 195d3efbe01SKonstantin Belousov } 196d3efbe01SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 197d3efbe01SKonstantin Belousov return (error); 198d3efbe01SKonstantin Belousov } 199d3efbe01SKonstantin Belousov 20082f4d640SKonstantin Belousov void 20182f4d640SKonstantin Belousov devfs_destroy_cdevpriv(struct cdev_privdata *p) 20282f4d640SKonstantin Belousov { 20382f4d640SKonstantin Belousov 20482f4d640SKonstantin Belousov mtx_assert(&cdevpriv_mtx, MA_OWNED); 205aeace3c3SKonstantin Belousov KASSERT(p->cdpd_fp->f_cdevpriv == p, 206aeace3c3SKonstantin Belousov ("devfs_destoy_cdevpriv %p != %p", p->cdpd_fp->f_cdevpriv, p)); 20782f4d640SKonstantin Belousov p->cdpd_fp->f_cdevpriv = NULL; 20882f4d640SKonstantin Belousov LIST_REMOVE(p, cdpd_list); 20982f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 21082f4d640SKonstantin Belousov (p->cdpd_dtr)(p->cdpd_data); 21182f4d640SKonstantin Belousov free(p, M_CDEVPDATA); 21282f4d640SKonstantin Belousov } 21382f4d640SKonstantin Belousov 214a53b7c69SKonstantin Belousov static void 21582f4d640SKonstantin Belousov devfs_fpdrop(struct file *fp) 21682f4d640SKonstantin Belousov { 21782f4d640SKonstantin Belousov struct cdev_privdata *p; 21882f4d640SKonstantin Belousov 21982f4d640SKonstantin Belousov mtx_lock(&cdevpriv_mtx); 22082f4d640SKonstantin Belousov if ((p = fp->f_cdevpriv) == NULL) { 22182f4d640SKonstantin Belousov mtx_unlock(&cdevpriv_mtx); 22282f4d640SKonstantin Belousov return; 22382f4d640SKonstantin Belousov } 22482f4d640SKonstantin Belousov devfs_destroy_cdevpriv(p); 22582f4d640SKonstantin Belousov } 22682f4d640SKonstantin Belousov 22782f4d640SKonstantin Belousov void 22882f4d640SKonstantin Belousov devfs_clear_cdevpriv(void) 22982f4d640SKonstantin Belousov { 23082f4d640SKonstantin Belousov struct file *fp; 23182f4d640SKonstantin Belousov 23282f4d640SKonstantin Belousov fp = curthread->td_fpop; 23382f4d640SKonstantin Belousov if (fp == NULL) 23482f4d640SKonstantin Belousov return; 23582f4d640SKonstantin Belousov devfs_fpdrop(fp); 23682f4d640SKonstantin Belousov } 23782f4d640SKonstantin Belousov 2383b444436SMateusz Guzik static void 2393b444436SMateusz Guzik devfs_usecount_add(struct vnode *vp) 2403b444436SMateusz Guzik { 2413b444436SMateusz Guzik struct devfs_dirent *de; 2423b444436SMateusz Guzik struct cdev *dev; 2433b444436SMateusz Guzik 2443b444436SMateusz Guzik mtx_lock(&devfs_de_interlock); 2453b444436SMateusz Guzik VI_LOCK(vp); 2463b444436SMateusz Guzik VNPASS(vp->v_type == VCHR || vp->v_type == VBAD, vp); 2473b444436SMateusz Guzik if (VN_IS_DOOMED(vp)) { 2483b444436SMateusz Guzik goto out_unlock; 2493b444436SMateusz Guzik } 2503b444436SMateusz Guzik 2513b444436SMateusz Guzik de = vp->v_data; 2523b444436SMateusz Guzik dev = vp->v_rdev; 2533b444436SMateusz Guzik MPASS(de != NULL); 2543b444436SMateusz Guzik MPASS(dev != NULL); 2553b444436SMateusz Guzik dev->si_usecount++; 2563b444436SMateusz Guzik de->de_usecount++; 2573b444436SMateusz Guzik out_unlock: 2583b444436SMateusz Guzik VI_UNLOCK(vp); 2593b444436SMateusz Guzik mtx_unlock(&devfs_de_interlock); 2603b444436SMateusz Guzik } 2613b444436SMateusz Guzik 2623b444436SMateusz Guzik static void 2633b444436SMateusz Guzik devfs_usecount_subl(struct vnode *vp) 2643b444436SMateusz Guzik { 2653b444436SMateusz Guzik struct devfs_dirent *de; 2663b444436SMateusz Guzik struct cdev *dev; 2673b444436SMateusz Guzik 2683b444436SMateusz Guzik mtx_assert(&devfs_de_interlock, MA_OWNED); 2693b444436SMateusz Guzik ASSERT_VI_LOCKED(vp, __func__); 2703b444436SMateusz Guzik VNPASS(vp->v_type == VCHR || vp->v_type == VBAD, vp); 2713b444436SMateusz Guzik 2723b444436SMateusz Guzik de = vp->v_data; 2733b444436SMateusz Guzik dev = vp->v_rdev; 2743b444436SMateusz Guzik if (de == NULL) 2753b444436SMateusz Guzik return; 2763b444436SMateusz Guzik if (dev == NULL) { 2773b444436SMateusz Guzik MPASS(de->de_usecount == 0); 2783b444436SMateusz Guzik return; 2793b444436SMateusz Guzik } 2803b444436SMateusz Guzik if (dev->si_usecount < de->de_usecount) 2813b444436SMateusz Guzik panic("%s: si_usecount underflow for dev %p " 2823b444436SMateusz Guzik "(has %ld, dirent has %d)\n", 2833b444436SMateusz Guzik __func__, dev, dev->si_usecount, de->de_usecount); 2843b444436SMateusz Guzik if (VN_IS_DOOMED(vp)) { 2853b444436SMateusz Guzik dev->si_usecount -= de->de_usecount; 2863b444436SMateusz Guzik de->de_usecount = 0; 2873b444436SMateusz Guzik } else { 2883b444436SMateusz Guzik if (de->de_usecount == 0) 2893b444436SMateusz Guzik panic("%s: de_usecount underflow for dev %p\n", 2903b444436SMateusz Guzik __func__, dev); 2913b444436SMateusz Guzik dev->si_usecount--; 2923b444436SMateusz Guzik de->de_usecount--; 2933b444436SMateusz Guzik } 2943b444436SMateusz Guzik } 2953b444436SMateusz Guzik 2963b444436SMateusz Guzik static void 2973b444436SMateusz Guzik devfs_usecount_sub(struct vnode *vp) 2983b444436SMateusz Guzik { 2993b444436SMateusz Guzik 3003b444436SMateusz Guzik mtx_lock(&devfs_de_interlock); 3013b444436SMateusz Guzik VI_LOCK(vp); 3023b444436SMateusz Guzik devfs_usecount_subl(vp); 3033b444436SMateusz Guzik VI_UNLOCK(vp); 3043b444436SMateusz Guzik mtx_unlock(&devfs_de_interlock); 3053b444436SMateusz Guzik } 3063b444436SMateusz Guzik 3073b444436SMateusz Guzik static int 3083b444436SMateusz Guzik devfs_usecountl(struct vnode *vp) 3093b444436SMateusz Guzik { 3103b444436SMateusz Guzik 3113b444436SMateusz Guzik VNPASS(vp->v_type == VCHR, vp); 3123b444436SMateusz Guzik mtx_assert(&devfs_de_interlock, MA_OWNED); 3133b444436SMateusz Guzik ASSERT_VI_LOCKED(vp, __func__); 3143b444436SMateusz Guzik return (vp->v_rdev->si_usecount); 3153b444436SMateusz Guzik } 3163b444436SMateusz Guzik 3173b444436SMateusz Guzik int 3183b444436SMateusz Guzik devfs_usecount(struct vnode *vp) 3193b444436SMateusz Guzik { 3203b444436SMateusz Guzik int count; 3213b444436SMateusz Guzik 3223b444436SMateusz Guzik VNPASS(vp->v_type == VCHR, vp); 3233b444436SMateusz Guzik mtx_lock(&devfs_de_interlock); 3243b444436SMateusz Guzik VI_LOCK(vp); 3253b444436SMateusz Guzik count = devfs_usecountl(vp); 3263b444436SMateusz Guzik VI_UNLOCK(vp); 3273b444436SMateusz Guzik mtx_unlock(&devfs_de_interlock); 3283b444436SMateusz Guzik return (count); 3293b444436SMateusz Guzik } 3303b444436SMateusz Guzik 3313b444436SMateusz Guzik void 3323b444436SMateusz Guzik devfs_ctty_ref(struct vnode *vp) 3333b444436SMateusz Guzik { 3343b444436SMateusz Guzik 3353b444436SMateusz Guzik vrefact(vp); 3363b444436SMateusz Guzik devfs_usecount_add(vp); 3373b444436SMateusz Guzik } 3383b444436SMateusz Guzik 3393b444436SMateusz Guzik void 3403b444436SMateusz Guzik devfs_ctty_unref(struct vnode *vp) 3413b444436SMateusz Guzik { 3423b444436SMateusz Guzik 3433b444436SMateusz Guzik devfs_usecount_sub(vp); 3443b444436SMateusz Guzik vrele(vp); 3453b444436SMateusz Guzik } 3463b444436SMateusz Guzik 3470f6bb099SJaakko Heinonen /* 3480f6bb099SJaakko Heinonen * On success devfs_populate_vp() returns with dmp->dm_lock held. 3490f6bb099SJaakko Heinonen */ 3500f6bb099SJaakko Heinonen static int 3510f6bb099SJaakko Heinonen devfs_populate_vp(struct vnode *vp) 3520f6bb099SJaakko Heinonen { 35389d10571SJaakko Heinonen struct devfs_dirent *de; 3540f6bb099SJaakko Heinonen struct devfs_mount *dmp; 3550f6bb099SJaakko Heinonen int locked; 3560f6bb099SJaakko Heinonen 3570f6bb099SJaakko Heinonen ASSERT_VOP_LOCKED(vp, "devfs_populate_vp"); 3580f6bb099SJaakko Heinonen 3590f6bb099SJaakko Heinonen dmp = VFSTODEVFS(vp->v_mount); 3607b19bddaSMateusz Guzik if (!devfs_populate_needed(dmp)) { 3617b19bddaSMateusz Guzik sx_xlock(&dmp->dm_lock); 3627b19bddaSMateusz Guzik goto out_nopopulate; 3637b19bddaSMateusz Guzik } 3647b19bddaSMateusz Guzik 3650f6bb099SJaakko Heinonen locked = VOP_ISLOCKED(vp); 3660f6bb099SJaakko Heinonen 3670f6bb099SJaakko Heinonen sx_xlock(&dmp->dm_lock); 3680f6bb099SJaakko Heinonen DEVFS_DMP_HOLD(dmp); 3690f6bb099SJaakko Heinonen 3700f6bb099SJaakko Heinonen /* Can't call devfs_populate() with the vnode lock held. */ 371b249ce48SMateusz Guzik VOP_UNLOCK(vp); 3720f6bb099SJaakko Heinonen devfs_populate(dmp); 3730f6bb099SJaakko Heinonen 3740f6bb099SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 3750f6bb099SJaakko Heinonen vn_lock(vp, locked | LK_RETRY); 3760f6bb099SJaakko Heinonen sx_xlock(&dmp->dm_lock); 3770f6bb099SJaakko Heinonen if (DEVFS_DMP_DROP(dmp)) { 3780f6bb099SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 3790f6bb099SJaakko Heinonen devfs_unmount_final(dmp); 380fb57d63eSKonstantin Belousov return (ERESTART); 3810f6bb099SJaakko Heinonen } 3827b19bddaSMateusz Guzik out_nopopulate: 383abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 38489d10571SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 385fb57d63eSKonstantin Belousov return (ERESTART); 38689d10571SJaakko Heinonen } 38789d10571SJaakko Heinonen de = vp->v_data; 38889d10571SJaakko Heinonen KASSERT(de != NULL, 38989d10571SJaakko Heinonen ("devfs_populate_vp: vp->v_data == NULL but vnode not doomed")); 39089d10571SJaakko Heinonen if ((de->de_flags & DE_DOOMED) != 0) { 3910f6bb099SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 392fb57d63eSKonstantin Belousov return (ERESTART); 3930f6bb099SJaakko Heinonen } 3940f6bb099SJaakko Heinonen 3950f6bb099SJaakko Heinonen return (0); 3960f6bb099SJaakko Heinonen } 3970f6bb099SJaakko Heinonen 3984c44fd37SJoe Marcus Clarke static int 3994c44fd37SJoe Marcus Clarke devfs_vptocnp(struct vop_vptocnp_args *ap) 4004c44fd37SJoe Marcus Clarke { 4014c44fd37SJoe Marcus Clarke struct vnode *vp = ap->a_vp; 4024c44fd37SJoe Marcus Clarke struct vnode **dvp = ap->a_vpp; 4034c44fd37SJoe Marcus Clarke struct devfs_mount *dmp; 4044c44fd37SJoe Marcus Clarke char *buf = ap->a_buf; 40545757984SMateusz Guzik size_t *buflen = ap->a_buflen; 4064c44fd37SJoe Marcus Clarke struct devfs_dirent *dd, *de; 4074c44fd37SJoe Marcus Clarke int i, error; 4084c44fd37SJoe Marcus Clarke 4094c44fd37SJoe Marcus Clarke dmp = VFSTODEVFS(vp->v_mount); 41089d10571SJaakko Heinonen 41189d10571SJaakko Heinonen error = devfs_populate_vp(vp); 41289d10571SJaakko Heinonen if (error != 0) 41389d10571SJaakko Heinonen return (error); 41489d10571SJaakko Heinonen 415e3fdd051SKonstantin Belousov if (vp->v_type != VCHR && vp->v_type != VDIR) { 416e3fdd051SKonstantin Belousov error = ENOENT; 4174c44fd37SJoe Marcus Clarke goto finished; 4184c44fd37SJoe Marcus Clarke } 419e3fdd051SKonstantin Belousov 420e3fdd051SKonstantin Belousov dd = vp->v_data; 421e3fdd051SKonstantin Belousov if (vp->v_type == VDIR && dd == dmp->dm_rootdir) { 4224c44fd37SJoe Marcus Clarke *dvp = vp; 423f82360acSKonstantin Belousov vref(*dvp); 4244c44fd37SJoe Marcus Clarke goto finished; 4254c44fd37SJoe Marcus Clarke } 426e3fdd051SKonstantin Belousov 427e3fdd051SKonstantin Belousov i = *buflen; 4284c44fd37SJoe Marcus Clarke i -= dd->de_dirent->d_namlen; 4294c44fd37SJoe Marcus Clarke if (i < 0) { 4304c44fd37SJoe Marcus Clarke error = ENOMEM; 4314c44fd37SJoe Marcus Clarke goto finished; 4324c44fd37SJoe Marcus Clarke } 433e3fdd051SKonstantin Belousov bcopy(dd->de_dirent->d_name, buf + i, dd->de_dirent->d_namlen); 4344c44fd37SJoe Marcus Clarke *buflen = i; 435e3fdd051SKonstantin Belousov de = devfs_parent_dirent(dd); 436f40645c8SJaakko Heinonen if (de == NULL) { 437f40645c8SJaakko Heinonen error = ENOENT; 438f40645c8SJaakko Heinonen goto finished; 439f40645c8SJaakko Heinonen } 4404c44fd37SJoe Marcus Clarke mtx_lock(&devfs_de_interlock); 4414c44fd37SJoe Marcus Clarke *dvp = de->de_vnode; 4424c44fd37SJoe Marcus Clarke if (*dvp != NULL) { 4434c44fd37SJoe Marcus Clarke VI_LOCK(*dvp); 4444c44fd37SJoe Marcus Clarke mtx_unlock(&devfs_de_interlock); 4454c44fd37SJoe Marcus Clarke vholdl(*dvp); 4464c44fd37SJoe Marcus Clarke VI_UNLOCK(*dvp); 447f82360acSKonstantin Belousov vref(*dvp); 448f82360acSKonstantin Belousov vdrop(*dvp); 449c7c7520aSKonstantin Belousov } else { 450c7c7520aSKonstantin Belousov mtx_unlock(&devfs_de_interlock); 4514c44fd37SJoe Marcus Clarke error = ENOENT; 452c7c7520aSKonstantin Belousov } 4534c44fd37SJoe Marcus Clarke finished: 4544c44fd37SJoe Marcus Clarke sx_xunlock(&dmp->dm_lock); 4554c44fd37SJoe Marcus Clarke return (error); 4564c44fd37SJoe Marcus Clarke } 4574c44fd37SJoe Marcus Clarke 4585a9300c4SPoul-Henning Kamp /* 4596adc5230SJaakko Heinonen * Construct the fully qualified path name relative to the mountpoint. 4606adc5230SJaakko Heinonen * If a NULL cnp is provided, no '/' is appended to the resulting path. 4615a9300c4SPoul-Henning Kamp */ 4626adc5230SJaakko Heinonen char * 4636adc5230SJaakko Heinonen devfs_fqpn(char *buf, struct devfs_mount *dmp, struct devfs_dirent *dd, 4646adc5230SJaakko Heinonen struct componentname *cnp) 4655a9300c4SPoul-Henning Kamp { 4665a9300c4SPoul-Henning Kamp int i; 4676adc5230SJaakko Heinonen struct devfs_dirent *de; 4685a9300c4SPoul-Henning Kamp 4696adc5230SJaakko Heinonen sx_assert(&dmp->dm_lock, SA_LOCKED); 4706adc5230SJaakko Heinonen 4715a9300c4SPoul-Henning Kamp i = SPECNAMELEN; 4725a9300c4SPoul-Henning Kamp buf[i] = '\0'; 4736adc5230SJaakko Heinonen if (cnp != NULL) 4745a9300c4SPoul-Henning Kamp i -= cnp->cn_namelen; 4755a9300c4SPoul-Henning Kamp if (i < 0) 4765a9300c4SPoul-Henning Kamp return (NULL); 4776adc5230SJaakko Heinonen if (cnp != NULL) 4785a9300c4SPoul-Henning Kamp bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); 4795a9300c4SPoul-Henning Kamp de = dd; 480d785dfefSPoul-Henning Kamp while (de != dmp->dm_rootdir) { 4816adc5230SJaakko Heinonen if (cnp != NULL || i < SPECNAMELEN) { 4825a9300c4SPoul-Henning Kamp i--; 4835a9300c4SPoul-Henning Kamp if (i < 0) 4845a9300c4SPoul-Henning Kamp return (NULL); 4855a9300c4SPoul-Henning Kamp buf[i] = '/'; 4866adc5230SJaakko Heinonen } 4875a9300c4SPoul-Henning Kamp i -= de->de_dirent->d_namlen; 4885a9300c4SPoul-Henning Kamp if (i < 0) 4895a9300c4SPoul-Henning Kamp return (NULL); 4905a9300c4SPoul-Henning Kamp bcopy(de->de_dirent->d_name, buf + i, 4915a9300c4SPoul-Henning Kamp de->de_dirent->d_namlen); 492f40645c8SJaakko Heinonen de = devfs_parent_dirent(de); 493f40645c8SJaakko Heinonen if (de == NULL) 494f40645c8SJaakko Heinonen return (NULL); 4955a9300c4SPoul-Henning Kamp } 4965a9300c4SPoul-Henning Kamp return (buf + i); 4975a9300c4SPoul-Henning Kamp } 4985a9300c4SPoul-Henning Kamp 499e7f9b744SKonstantin Belousov static int 500e7f9b744SKonstantin Belousov devfs_allocv_drop_refs(int drop_dm_lock, struct devfs_mount *dmp, 501e7f9b744SKonstantin Belousov struct devfs_dirent *de) 502e7f9b744SKonstantin Belousov { 503e7f9b744SKonstantin Belousov int not_found; 504e7f9b744SKonstantin Belousov 505e7f9b744SKonstantin Belousov not_found = 0; 506e7f9b744SKonstantin Belousov if (de->de_flags & DE_DOOMED) 507e7f9b744SKonstantin Belousov not_found = 1; 508e7f9b744SKonstantin Belousov if (DEVFS_DE_DROP(de)) { 509e7f9b744SKonstantin Belousov KASSERT(not_found == 1, ("DEVFS de dropped but not doomed")); 510e7f9b744SKonstantin Belousov devfs_dirent_free(de); 511e7f9b744SKonstantin Belousov } 512e7f9b744SKonstantin Belousov if (DEVFS_DMP_DROP(dmp)) { 513e7f9b744SKonstantin Belousov KASSERT(not_found == 1, 514e7f9b744SKonstantin Belousov ("DEVFS mount struct freed before dirent")); 515e7f9b744SKonstantin Belousov not_found = 2; 516e7f9b744SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 517e7f9b744SKonstantin Belousov devfs_unmount_final(dmp); 518e7f9b744SKonstantin Belousov } 519af72db71SKonstantin Belousov if (not_found == 1 || (drop_dm_lock && not_found != 2)) 520e7f9b744SKonstantin Belousov sx_unlock(&dmp->dm_lock); 521e7f9b744SKonstantin Belousov return (not_found); 522e7f9b744SKonstantin Belousov } 523e7f9b744SKonstantin Belousov 524e7f9b744SKonstantin Belousov /* 525e7f9b744SKonstantin Belousov * devfs_allocv shall be entered with dmp->dm_lock held, and it drops 526e7f9b744SKonstantin Belousov * it on return. 527e7f9b744SKonstantin Belousov */ 528c32d0a1dSPoul-Henning Kamp int 5299968a426SKonstantin Belousov devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode, 5309968a426SKonstantin Belousov struct vnode **vpp) 5313f54a085SPoul-Henning Kamp { 5323f54a085SPoul-Henning Kamp int error; 5333f54a085SPoul-Henning Kamp struct vnode *vp; 53489c9c53dSPoul-Henning Kamp struct cdev *dev; 535e7f9b744SKonstantin Belousov struct devfs_mount *dmp; 5363a6fc63cSKonstantin Belousov struct cdevsw *dsw; 537f9c13ab8SMateusz Guzik enum vgetstate vs; 5383f54a085SPoul-Henning Kamp 539e7f9b744SKonstantin Belousov dmp = VFSTODEVFS(mp); 540e7f9b744SKonstantin Belousov if (de->de_flags & DE_DOOMED) { 541e7f9b744SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 542e7f9b744SKonstantin Belousov return (ENOENT); 543e7f9b744SKonstantin Belousov } 544724ce55bSKonstantin Belousov loop: 545e7f9b744SKonstantin Belousov DEVFS_DE_HOLD(de); 546e7f9b744SKonstantin Belousov DEVFS_DMP_HOLD(dmp); 54756eeb277SStephan Uphoff mtx_lock(&devfs_de_interlock); 5483f54a085SPoul-Henning Kamp vp = de->de_vnode; 5493f54a085SPoul-Henning Kamp if (vp != NULL) { 550f9c13ab8SMateusz Guzik vs = vget_prep(vp); 55156eeb277SStephan Uphoff mtx_unlock(&devfs_de_interlock); 552e7f9b744SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 553f9c13ab8SMateusz Guzik vget_finish(vp, lockmode | LK_RETRY, vs); 554e7f9b744SKonstantin Belousov sx_xlock(&dmp->dm_lock); 555e7f9b744SKonstantin Belousov if (devfs_allocv_drop_refs(0, dmp, de)) { 556e7f9b744SKonstantin Belousov vput(vp); 557e7f9b744SKonstantin Belousov return (ENOENT); 5586d79564fSKonstantin Belousov } else if (VN_IS_DOOMED(vp)) { 559724ce55bSKonstantin Belousov mtx_lock(&devfs_de_interlock); 560724ce55bSKonstantin Belousov if (de->de_vnode == vp) { 561724ce55bSKonstantin Belousov de->de_vnode = NULL; 562724ce55bSKonstantin Belousov vp->v_data = NULL; 563724ce55bSKonstantin Belousov } 564724ce55bSKonstantin Belousov mtx_unlock(&devfs_de_interlock); 565724ce55bSKonstantin Belousov vput(vp); 566724ce55bSKonstantin Belousov goto loop; 567772e2453SKonstantin Belousov } 568e7f9b744SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 5693f54a085SPoul-Henning Kamp *vpp = vp; 5703f54a085SPoul-Henning Kamp return (0); 5713f54a085SPoul-Henning Kamp } 57256eeb277SStephan Uphoff mtx_unlock(&devfs_de_interlock); 57393bcdfe2SPoul-Henning Kamp if (de->de_dirent->d_type == DT_CHR) { 574e7f9b744SKonstantin Belousov if (!(de->de_cdp->cdp_flags & CDP_ACTIVE)) { 575e7f9b744SKonstantin Belousov devfs_allocv_drop_refs(1, dmp, de); 57693bcdfe2SPoul-Henning Kamp return (ENOENT); 577e7f9b744SKonstantin Belousov } 578e606a3c6SPoul-Henning Kamp dev = &de->de_cdp->cdp_c; 57993bcdfe2SPoul-Henning Kamp } else { 580f3732fd1SPoul-Henning Kamp dev = NULL; 58193bcdfe2SPoul-Henning Kamp } 582aec0fb7bSPoul-Henning Kamp error = getnewvnode("devfs", mp, &devfs_vnodeops, &vp); 5833f54a085SPoul-Henning Kamp if (error != 0) { 584e7f9b744SKonstantin Belousov devfs_allocv_drop_refs(1, dmp, de); 5853f54a085SPoul-Henning Kamp printf("devfs_allocv: failed to allocate new vnode\n"); 5863f54a085SPoul-Henning Kamp return (error); 5873f54a085SPoul-Henning Kamp } 5883f54a085SPoul-Henning Kamp 5893f54a085SPoul-Henning Kamp if (de->de_dirent->d_type == DT_CHR) { 5903f54a085SPoul-Henning Kamp vp->v_type = VCHR; 59120a92a18SPoul-Henning Kamp VI_LOCK(vp); 59220a92a18SPoul-Henning Kamp dev_lock(); 593eb151cb9SPoul-Henning Kamp dev_refl(dev); 59457fd3d55SPawel Jakub Dawidek /* XXX: v_rdev should be protect by vnode lock */ 59520a92a18SPoul-Henning Kamp vp->v_rdev = dev; 596f1fa1ba3SMateusz Guzik VNPASS(vp->v_usecount == 1, vp); 5973a6fc63cSKonstantin Belousov /* Special casing of ttys for deadfs. Probably redundant. */ 5983a6fc63cSKonstantin Belousov dsw = dev->si_devsw; 5993a6fc63cSKonstantin Belousov if (dsw != NULL && (dsw->d_flags & D_TTY) != 0) 6003a6fc63cSKonstantin Belousov vp->v_vflag |= VV_ISTTY; 60120a92a18SPoul-Henning Kamp dev_unlock(); 60220a92a18SPoul-Henning Kamp VI_UNLOCK(vp); 6033979450bSKonstantin Belousov if ((dev->si_flags & SI_ETERNAL) != 0) 6043979450bSKonstantin Belousov vp->v_vflag |= VV_ETERNALDEV; 605aec0fb7bSPoul-Henning Kamp vp->v_op = &devfs_specops; 6063f54a085SPoul-Henning Kamp } else if (de->de_dirent->d_type == DT_DIR) { 6073f54a085SPoul-Henning Kamp vp->v_type = VDIR; 6083f54a085SPoul-Henning Kamp } else if (de->de_dirent->d_type == DT_LNK) { 6093f54a085SPoul-Henning Kamp vp->v_type = VLNK; 6103f54a085SPoul-Henning Kamp } else { 6113f54a085SPoul-Henning Kamp vp->v_type = VBAD; 6123f54a085SPoul-Henning Kamp } 6139e40a5f8SKonstantin Belousov vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOWITNESS); 6143634d5b2SJohn Baldwin VN_LOCK_ASHARE(vp); 61556eeb277SStephan Uphoff mtx_lock(&devfs_de_interlock); 616a481b90bSPoul-Henning Kamp vp->v_data = de; 6173f54a085SPoul-Henning Kamp de->de_vnode = vp; 61856eeb277SStephan Uphoff mtx_unlock(&devfs_de_interlock); 61966c5fbcaSKonstantin Belousov error = insmntque1(vp, mp); 62061b9d89fSTor Egge if (error != 0) { 62166c5fbcaSKonstantin Belousov mtx_lock(&devfs_de_interlock); 62266c5fbcaSKonstantin Belousov vp->v_data = NULL; 62366c5fbcaSKonstantin Belousov de->de_vnode = NULL; 62466c5fbcaSKonstantin Belousov mtx_unlock(&devfs_de_interlock); 62566c5fbcaSKonstantin Belousov vgone(vp); 62666c5fbcaSKonstantin Belousov vput(vp); 62761b9d89fSTor Egge (void) devfs_allocv_drop_refs(1, dmp, de); 62861b9d89fSTor Egge return (error); 62961b9d89fSTor Egge } 630e7f9b744SKonstantin Belousov if (devfs_allocv_drop_refs(0, dmp, de)) { 631829f0bcbSMateusz Guzik vgone(vp); 632e7f9b744SKonstantin Belousov vput(vp); 633e7f9b744SKonstantin Belousov return (ENOENT); 634e7f9b744SKonstantin Belousov } 6356742f328SRobert Watson #ifdef MAC 63630d239bcSRobert Watson mac_devfs_vnode_associate(mp, de, vp); 6376742f328SRobert Watson #endif 638e7f9b744SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 639829f0bcbSMateusz Guzik vn_set_state(vp, VSTATE_CONSTRUCTED); 6403f54a085SPoul-Henning Kamp *vpp = vp; 6413f54a085SPoul-Henning Kamp return (0); 6423f54a085SPoul-Henning Kamp } 6433f54a085SPoul-Henning Kamp 6443f54a085SPoul-Henning Kamp static int 64521806f30SPoul-Henning Kamp devfs_access(struct vop_access_args *ap) 6463f54a085SPoul-Henning Kamp { 6473f54a085SPoul-Henning Kamp struct vnode *vp = ap->a_vp; 648fcc9b84cSPoul-Henning Kamp struct devfs_dirent *de; 6494dba07b2SMateusz Guzik struct proc *p; 6509c71cb4bSPoul-Henning Kamp int error; 6513f54a085SPoul-Henning Kamp 652fcc9b84cSPoul-Henning Kamp de = vp->v_data; 653a481b90bSPoul-Henning Kamp if (vp->v_type == VDIR) 654a481b90bSPoul-Henning Kamp de = de->de_dir; 6553f54a085SPoul-Henning Kamp 6569c71cb4bSPoul-Henning Kamp error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 657d292b194SMateusz Guzik ap->a_accmode, ap->a_cred); 6588dc9b4cfSEd Schouten if (error == 0) 6598dc9b4cfSEd Schouten return (0); 6609c71cb4bSPoul-Henning Kamp if (error != EACCES) 6619c71cb4bSPoul-Henning Kamp return (error); 6624dba07b2SMateusz Guzik p = ap->a_td->td_proc; 6639c71cb4bSPoul-Henning Kamp /* We do, however, allow access to the controlling terminal */ 6644dba07b2SMateusz Guzik PROC_LOCK(p); 6654dba07b2SMateusz Guzik if (!(p->p_flag & P_CONTROLT)) { 6664dba07b2SMateusz Guzik PROC_UNLOCK(p); 6679c71cb4bSPoul-Henning Kamp return (error); 6684dba07b2SMateusz Guzik } 6694dba07b2SMateusz Guzik if (p->p_session->s_ttydp == de->de_cdp) 6704dba07b2SMateusz Guzik error = 0; 6714dba07b2SMateusz Guzik PROC_UNLOCK(p); 6729c71cb4bSPoul-Henning Kamp return (error); 6733f54a085SPoul-Henning Kamp } 6743f54a085SPoul-Henning Kamp 675cccac8a1SKonstantin Belousov _Static_assert(((FMASK | FCNTLFLAGS) & (FLASTCLOSE | FREVOKE)) == 0, 676cccac8a1SKonstantin Belousov "devfs-only flag reuse failed"); 677cccac8a1SKonstantin Belousov 678ff7c5a48SPoul-Henning Kamp static int 67921806f30SPoul-Henning Kamp devfs_close(struct vop_close_args *ap) 680ff7c5a48SPoul-Henning Kamp { 681ff7c5a48SPoul-Henning Kamp struct vnode *vp = ap->a_vp, *oldvp; 682ff7c5a48SPoul-Henning Kamp struct thread *td = ap->a_td; 6834dba07b2SMateusz Guzik struct proc *p; 684ff7c5a48SPoul-Henning Kamp struct cdev *dev = vp->v_rdev; 685ff7c5a48SPoul-Henning Kamp struct cdevsw *dsw; 6863b444436SMateusz Guzik struct devfs_dirent *de = vp->v_data; 687cccac8a1SKonstantin Belousov int dflags, error, ref, vp_locked; 688ff7c5a48SPoul-Henning Kamp 689ff7c5a48SPoul-Henning Kamp /* 69059e0452eSJaakko Heinonen * XXX: Don't call d_close() if we were called because of 6913af3e99cSMateusz Guzik * XXX: insmntque() failure. 69259e0452eSJaakko Heinonen */ 69359e0452eSJaakko Heinonen if (vp->v_data == NULL) 69459e0452eSJaakko Heinonen return (0); 69559e0452eSJaakko Heinonen 69659e0452eSJaakko Heinonen /* 697ff7c5a48SPoul-Henning Kamp * Hack: a tty device that is a controlling terminal 698ff7c5a48SPoul-Henning Kamp * has a reference from the session structure. 699ff7c5a48SPoul-Henning Kamp * We cannot easily tell that a character device is 700ff7c5a48SPoul-Henning Kamp * a controlling terminal, unless it is the closing 701ff7c5a48SPoul-Henning Kamp * process' controlling terminal. In that case, 702ff7c5a48SPoul-Henning Kamp * if the reference count is 2 (this last descriptor 703ff7c5a48SPoul-Henning Kamp * plus the session), release the reference from the session. 704ff7c5a48SPoul-Henning Kamp */ 7053b444436SMateusz Guzik if (de->de_usecount == 2 && td != NULL) { 7064dba07b2SMateusz Guzik p = td->td_proc; 7074dba07b2SMateusz Guzik PROC_LOCK(p); 7084dba07b2SMateusz Guzik if (vp == p->p_session->s_ttyvp) { 7094dba07b2SMateusz Guzik PROC_UNLOCK(p); 7103a222fe0SMateusz Guzik oldvp = NULL; 7111d1b55fbSMateusz Guzik sx_xlock(&proctree_lock); 7124dba07b2SMateusz Guzik if (vp == p->p_session->s_ttyvp) { 7134dba07b2SMateusz Guzik SESS_LOCK(p->p_session); 7143b444436SMateusz Guzik mtx_lock(&devfs_de_interlock); 715ff7c5a48SPoul-Henning Kamp VI_LOCK(vp); 7163b444436SMateusz Guzik if (devfs_usecountl(vp) == 2 && !VN_IS_DOOMED(vp)) { 7174dba07b2SMateusz Guzik p->p_session->s_ttyvp = NULL; 7184dba07b2SMateusz Guzik p->p_session->s_ttydp = NULL; 719ff7c5a48SPoul-Henning Kamp oldvp = vp; 720ff7c5a48SPoul-Henning Kamp } 721ff7c5a48SPoul-Henning Kamp VI_UNLOCK(vp); 7223b444436SMateusz Guzik mtx_unlock(&devfs_de_interlock); 7234dba07b2SMateusz Guzik SESS_UNLOCK(p->p_session); 724ff7c5a48SPoul-Henning Kamp } 725ff7c5a48SPoul-Henning Kamp sx_xunlock(&proctree_lock); 726ff7c5a48SPoul-Henning Kamp if (oldvp != NULL) 7273b444436SMateusz Guzik devfs_ctty_unref(oldvp); 7284dba07b2SMateusz Guzik } else 7294dba07b2SMateusz Guzik PROC_UNLOCK(p); 7303a222fe0SMateusz Guzik } 731ff7c5a48SPoul-Henning Kamp /* 732ff7c5a48SPoul-Henning Kamp * We do not want to really close the device if it 733ff7c5a48SPoul-Henning Kamp * is still in use unless we are trying to close it 734ff7c5a48SPoul-Henning Kamp * forcibly. Since every use (buffer, vnode, swap, cmap) 735ff7c5a48SPoul-Henning Kamp * holds a reference to the vnode, and because we mark 736ff7c5a48SPoul-Henning Kamp * any other vnodes that alias this device, when the 737ff7c5a48SPoul-Henning Kamp * sum of the reference counts on all the aliased 738ff7c5a48SPoul-Henning Kamp * vnodes descends to one, we are on last close. 739ff7c5a48SPoul-Henning Kamp */ 7403979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 741ff7c5a48SPoul-Henning Kamp if (dsw == NULL) 742ff7c5a48SPoul-Henning Kamp return (ENXIO); 743cccac8a1SKonstantin Belousov dflags = 0; 7443b444436SMateusz Guzik mtx_lock(&devfs_de_interlock); 745ff7c5a48SPoul-Henning Kamp VI_LOCK(vp); 7463b444436SMateusz Guzik if (devfs_usecountl(vp) == 1) 7471fccb43cSMateusz Guzik dflags |= FLASTCLOSE; 7483b444436SMateusz Guzik devfs_usecount_subl(vp); 7493b444436SMateusz Guzik mtx_unlock(&devfs_de_interlock); 750abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 751ff7c5a48SPoul-Henning Kamp /* Forced close. */ 752cccac8a1SKonstantin Belousov dflags |= FREVOKE | FNONBLOCK; 753ff7c5a48SPoul-Henning Kamp } else if (dsw->d_flags & D_TRACKCLOSE) { 754ff7c5a48SPoul-Henning Kamp /* Keep device updated on status. */ 7551fccb43cSMateusz Guzik } else if ((dflags & FLASTCLOSE) == 0) { 756ff7c5a48SPoul-Henning Kamp VI_UNLOCK(vp); 7573979450bSKonstantin Belousov dev_relthread(dev, ref); 758ff7c5a48SPoul-Henning Kamp return (0); 759ff7c5a48SPoul-Henning Kamp } 7601fccb43cSMateusz Guzik vholdnz(vp); 761ff7c5a48SPoul-Henning Kamp VI_UNLOCK(vp); 76281c794f9SAttilio Rao vp_locked = VOP_ISLOCKED(vp); 763b249ce48SMateusz Guzik VOP_UNLOCK(vp); 764ff7c5a48SPoul-Henning Kamp KASSERT(dev->si_refcount > 0, 765ff7c5a48SPoul-Henning Kamp ("devfs_close() on un-referenced struct cdev *(%s)", devtoname(dev))); 766cccac8a1SKonstantin Belousov error = dsw->d_close(dev, ap->a_fflag | dflags, S_IFCHR, td); 7673979450bSKonstantin Belousov dev_relthread(dev, ref); 768cb05b60aSAttilio Rao vn_lock(vp, vp_locked | LK_RETRY); 769828d6d12SKonstantin Belousov vdrop(vp); 770ff7c5a48SPoul-Henning Kamp return (error); 771ff7c5a48SPoul-Henning Kamp } 772ff7c5a48SPoul-Henning Kamp 77356dd3a61SPoul-Henning Kamp static int 77456dd3a61SPoul-Henning Kamp devfs_close_f(struct file *fp, struct thread *td) 77556dd3a61SPoul-Henning Kamp { 77682f4d640SKonstantin Belousov int error; 7777818e0a5SKonstantin Belousov struct file *fpop; 77856dd3a61SPoul-Henning Kamp 779e517e6f1SJohn Baldwin /* 780e517e6f1SJohn Baldwin * NB: td may be NULL if this descriptor is closed due to 781e517e6f1SJohn Baldwin * garbage collection from a closed UNIX domain socket. 782e517e6f1SJohn Baldwin */ 783e517e6f1SJohn Baldwin fpop = curthread->td_fpop; 784e517e6f1SJohn Baldwin curthread->td_fpop = fp; 78582f4d640SKonstantin Belousov error = vnops.fo_close(fp, td); 786e517e6f1SJohn Baldwin curthread->td_fpop = fpop; 787dccc45e4SJohn Baldwin 788dccc45e4SJohn Baldwin /* 789dccc45e4SJohn Baldwin * The f_cdevpriv cannot be assigned non-NULL value while we 790dccc45e4SJohn Baldwin * are destroying the file. 791dccc45e4SJohn Baldwin */ 792dccc45e4SJohn Baldwin if (fp->f_cdevpriv != NULL) 793dccc45e4SJohn Baldwin devfs_fpdrop(fp); 79482f4d640SKonstantin Belousov return (error); 79556dd3a61SPoul-Henning Kamp } 79656dd3a61SPoul-Henning Kamp 797ff7c5a48SPoul-Henning Kamp static int 79821806f30SPoul-Henning Kamp devfs_getattr(struct vop_getattr_args *ap) 7993f54a085SPoul-Henning Kamp { 8003f54a085SPoul-Henning Kamp struct vnode *vp = ap->a_vp; 8013f54a085SPoul-Henning Kamp struct vattr *vap = ap->a_vap; 8023f54a085SPoul-Henning Kamp struct devfs_dirent *de; 803f5efcd64SJaakko Heinonen struct devfs_mount *dmp; 80489c9c53dSPoul-Henning Kamp struct cdev *dev; 805584b675eSKonstantin Belousov struct timeval boottime; 806584b675eSKonstantin Belousov int error; 8073f54a085SPoul-Henning Kamp 808f5efcd64SJaakko Heinonen error = devfs_populate_vp(vp); 809f5efcd64SJaakko Heinonen if (error != 0) 810f5efcd64SJaakko Heinonen return (error); 811f5efcd64SJaakko Heinonen 812f5efcd64SJaakko Heinonen dmp = VFSTODEVFS(vp->v_mount); 813f5efcd64SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 814f5efcd64SJaakko Heinonen 8153f54a085SPoul-Henning Kamp de = vp->v_data; 8162c022012SPoul-Henning Kamp KASSERT(de != NULL, ("Null dirent in devfs_getattr vp=%p", vp)); 8172c022012SPoul-Henning Kamp if (vp->v_type == VDIR) { 818a481b90bSPoul-Henning Kamp de = de->de_dir; 8192c022012SPoul-Henning Kamp KASSERT(de != NULL, 8202c022012SPoul-Henning Kamp ("Null dir dirent in devfs_getattr vp=%p", vp)); 8212c022012SPoul-Henning Kamp } 8223f54a085SPoul-Henning Kamp vap->va_uid = de->de_uid; 8233f54a085SPoul-Henning Kamp vap->va_gid = de->de_gid; 8243f54a085SPoul-Henning Kamp vap->va_mode = de->de_mode; 825aadf2655SPoul-Henning Kamp if (vp->v_type == VLNK) 826bc553559SPoul-Henning Kamp vap->va_size = strlen(de->de_symlink); 8272ab80ed8SDima Dorfman else if (vp->v_type == VDIR) 8282ab80ed8SDima Dorfman vap->va_size = vap->va_bytes = DEV_BSIZE; 829aadf2655SPoul-Henning Kamp else 8303f54a085SPoul-Henning Kamp vap->va_size = 0; 8312ab80ed8SDima Dorfman if (vp->v_type != VDIR) 8322ab80ed8SDima Dorfman vap->va_bytes = 0; 8333f54a085SPoul-Henning Kamp vap->va_blocksize = DEV_BSIZE; 83493bcdfe2SPoul-Henning Kamp vap->va_type = vp->v_type; 8354b1c62b3SPoul-Henning Kamp 836584b675eSKonstantin Belousov getboottime(&boottime); 8374b1c62b3SPoul-Henning Kamp #define fix(aa) \ 8384b1c62b3SPoul-Henning Kamp do { \ 839164554deSTom Rhodes if ((aa).tv_sec <= 3600) { \ 8404b1c62b3SPoul-Henning Kamp (aa).tv_sec = boottime.tv_sec; \ 8414b1c62b3SPoul-Henning Kamp (aa).tv_nsec = boottime.tv_usec * 1000; \ 8424b1c62b3SPoul-Henning Kamp } \ 8434b1c62b3SPoul-Henning Kamp } while (0) 8444b1c62b3SPoul-Henning Kamp 845a481b90bSPoul-Henning Kamp if (vp->v_type != VCHR) { 8464b1c62b3SPoul-Henning Kamp fix(de->de_atime); 8473f54a085SPoul-Henning Kamp vap->va_atime = de->de_atime; 8484b1c62b3SPoul-Henning Kamp fix(de->de_mtime); 8493f54a085SPoul-Henning Kamp vap->va_mtime = de->de_mtime; 8504b1c62b3SPoul-Henning Kamp fix(de->de_ctime); 8513f54a085SPoul-Henning Kamp vap->va_ctime = de->de_ctime; 852a481b90bSPoul-Henning Kamp } else { 853a481b90bSPoul-Henning Kamp dev = vp->v_rdev; 8544b1c62b3SPoul-Henning Kamp fix(dev->si_atime); 855a481b90bSPoul-Henning Kamp vap->va_atime = dev->si_atime; 8564b1c62b3SPoul-Henning Kamp fix(dev->si_mtime); 857a481b90bSPoul-Henning Kamp vap->va_mtime = dev->si_mtime; 8584b1c62b3SPoul-Henning Kamp fix(dev->si_ctime); 859a481b90bSPoul-Henning Kamp vap->va_ctime = dev->si_ctime; 860b43ab0e3SPoul-Henning Kamp 86105427aafSKonstantin Belousov vap->va_rdev = cdev2priv(dev)->cdp_inode; 862a481b90bSPoul-Henning Kamp } 8633f54a085SPoul-Henning Kamp vap->va_gen = 0; 8643f54a085SPoul-Henning Kamp vap->va_flags = 0; 865caf8aec8SKonstantin Belousov vap->va_filerev = 0; 866a481b90bSPoul-Henning Kamp vap->va_nlink = de->de_links; 8673f54a085SPoul-Henning Kamp vap->va_fileid = de->de_inode; 8683f54a085SPoul-Henning Kamp 8693f54a085SPoul-Henning Kamp return (error); 8703f54a085SPoul-Henning Kamp } 8713f54a085SPoul-Henning Kamp 872ff7c5a48SPoul-Henning Kamp /* ARGSUSED */ 8733f54a085SPoul-Henning Kamp static int 87456dd3a61SPoul-Henning Kamp devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struct thread *td) 87556dd3a61SPoul-Henning Kamp { 8767818e0a5SKonstantin Belousov struct file *fpop; 877af326aceSConrad Meyer int error; 87856dd3a61SPoul-Henning Kamp 8797818e0a5SKonstantin Belousov fpop = td->td_fpop; 880af326aceSConrad Meyer td->td_fpop = fp; 881f12aa60cSKonstantin Belousov error = vnops.fo_ioctl(fp, com, data, cred, td); 882af326aceSConrad Meyer td->td_fpop = fpop; 883aac5167cSPoul-Henning Kamp return (error); 884f12aa60cSKonstantin Belousov } 88556dd3a61SPoul-Henning Kamp 886ed34a7fcSBrooks Davis void * 887ed34a7fcSBrooks Davis fiodgname_buf_get_ptr(void *fgnp, u_long com) 888ed34a7fcSBrooks Davis { 889ed34a7fcSBrooks Davis union { 890ed34a7fcSBrooks Davis struct fiodgname_arg fgn; 891ed34a7fcSBrooks Davis #ifdef COMPAT_FREEBSD32 892ed34a7fcSBrooks Davis struct fiodgname_arg32 fgn32; 893ed34a7fcSBrooks Davis #endif 894ed34a7fcSBrooks Davis } *fgnup; 895ed34a7fcSBrooks Davis 896ed34a7fcSBrooks Davis fgnup = fgnp; 897ed34a7fcSBrooks Davis switch (com) { 898ed34a7fcSBrooks Davis case FIODGNAME: 899ed34a7fcSBrooks Davis return (fgnup->fgn.buf); 900ed34a7fcSBrooks Davis #ifdef COMPAT_FREEBSD32 901ed34a7fcSBrooks Davis case FIODGNAME_32: 902ed34a7fcSBrooks Davis return ((void *)(uintptr_t)fgnup->fgn32.buf); 903ed34a7fcSBrooks Davis #endif 904ed34a7fcSBrooks Davis default: 905ed34a7fcSBrooks Davis panic("Unhandled ioctl command %ld", com); 906ed34a7fcSBrooks Davis } 907ed34a7fcSBrooks Davis } 908ed34a7fcSBrooks Davis 909af326aceSConrad Meyer static int 910af326aceSConrad Meyer devfs_ioctl(struct vop_ioctl_args *ap) 911af326aceSConrad Meyer { 912af326aceSConrad Meyer struct fiodgname_arg *fgn; 913af326aceSConrad Meyer struct vnode *vpold, *vp; 914af326aceSConrad Meyer struct cdevsw *dsw; 915af326aceSConrad Meyer struct thread *td; 91611c345b1SMateusz Guzik struct session *sess; 917af326aceSConrad Meyer struct cdev *dev; 918af326aceSConrad Meyer int error, ref, i; 919af326aceSConrad Meyer const char *p; 920af326aceSConrad Meyer u_long com; 921af326aceSConrad Meyer 922af326aceSConrad Meyer vp = ap->a_vp; 923af326aceSConrad Meyer com = ap->a_command; 924af326aceSConrad Meyer td = ap->a_td; 925af326aceSConrad Meyer 926af326aceSConrad Meyer dsw = devvn_refthread(vp, &dev, &ref); 927af326aceSConrad Meyer if (dsw == NULL) 928af326aceSConrad Meyer return (ENXIO); 929af326aceSConrad Meyer KASSERT(dev->si_refcount > 0, 930af326aceSConrad Meyer ("devfs: un-referenced struct cdev *(%s)", devtoname(dev))); 931af326aceSConrad Meyer 932ed34a7fcSBrooks Davis switch (com) { 933ed34a7fcSBrooks Davis case FIODTYPE: 934af326aceSConrad Meyer *(int *)ap->a_data = dsw->d_flags & D_TYPEMASK; 935af326aceSConrad Meyer error = 0; 936ed34a7fcSBrooks Davis break; 937ed34a7fcSBrooks Davis case FIODGNAME: 938ed34a7fcSBrooks Davis #ifdef COMPAT_FREEBSD32 939ed34a7fcSBrooks Davis case FIODGNAME_32: 940ed34a7fcSBrooks Davis #endif 941af326aceSConrad Meyer fgn = ap->a_data; 94226474078SPoul-Henning Kamp p = devtoname(dev); 94326474078SPoul-Henning Kamp i = strlen(p) + 1; 94426474078SPoul-Henning Kamp if (i > fgn->len) 94580447bf7SPoul-Henning Kamp error = EINVAL; 94680447bf7SPoul-Henning Kamp else 947ed34a7fcSBrooks Davis error = copyout(p, fiodgname_buf_get_ptr(fgn, com), i); 948ed34a7fcSBrooks Davis break; 949ed34a7fcSBrooks Davis default: 950ed34a7fcSBrooks Davis error = dsw->d_ioctl(dev, com, ap->a_data, ap->a_fflag, td); 95156dd3a61SPoul-Henning Kamp } 952af326aceSConrad Meyer 9533979450bSKonstantin Belousov dev_relthread(dev, ref); 95456dd3a61SPoul-Henning Kamp if (error == ENOIOCTL) 95556dd3a61SPoul-Henning Kamp error = ENOTTY; 95656dd3a61SPoul-Henning Kamp 957af326aceSConrad Meyer if (error == 0 && com == TIOCSCTTY) { 9581b50b999SKyle Evans /* 9591b50b999SKyle Evans * Do nothing if reassigning same control tty, or if the 9601b50b999SKyle Evans * control tty has already disappeared. If it disappeared, 9611b50b999SKyle Evans * it's because we were racing with TIOCNOTTY. TIOCNOTTY 9621b50b999SKyle Evans * already took care of releasing the old vnode and we have 9631b50b999SKyle Evans * nothing left to do. 9641b50b999SKyle Evans */ 96556dd3a61SPoul-Henning Kamp sx_slock(&proctree_lock); 96611c345b1SMateusz Guzik sess = td->td_proc->p_session; 96711c345b1SMateusz Guzik if (sess->s_ttyvp == vp || sess->s_ttyp == NULL) { 96856dd3a61SPoul-Henning Kamp sx_sunlock(&proctree_lock); 96956dd3a61SPoul-Henning Kamp return (0); 97056dd3a61SPoul-Henning Kamp } 97156dd3a61SPoul-Henning Kamp 9723b444436SMateusz Guzik devfs_ctty_ref(vp); 97311c345b1SMateusz Guzik SESS_LOCK(sess); 97411c345b1SMateusz Guzik vpold = sess->s_ttyvp; 97511c345b1SMateusz Guzik sess->s_ttyvp = vp; 97611c345b1SMateusz Guzik sess->s_ttydp = cdev2priv(dev); 97711c345b1SMateusz Guzik SESS_UNLOCK(sess); 97856dd3a61SPoul-Henning Kamp 97956dd3a61SPoul-Henning Kamp sx_sunlock(&proctree_lock); 98056dd3a61SPoul-Henning Kamp 98156dd3a61SPoul-Henning Kamp /* Get rid of reference to old control tty */ 98256dd3a61SPoul-Henning Kamp if (vpold) 9833bc17248SMateusz Guzik devfs_ctty_unref(vpold); 98456dd3a61SPoul-Henning Kamp } 98556dd3a61SPoul-Henning Kamp return (error); 98656dd3a61SPoul-Henning Kamp } 98756dd3a61SPoul-Henning Kamp 988ff7c5a48SPoul-Henning Kamp /* ARGSUSED */ 989ff7c5a48SPoul-Henning Kamp static int 99056dd3a61SPoul-Henning Kamp devfs_kqfilter_f(struct file *fp, struct knote *kn) 99156dd3a61SPoul-Henning Kamp { 99256dd3a61SPoul-Henning Kamp struct cdev *dev; 99356dd3a61SPoul-Henning Kamp struct cdevsw *dsw; 9943979450bSKonstantin Belousov int error, ref; 9957818e0a5SKonstantin Belousov struct file *fpop; 9967818e0a5SKonstantin Belousov struct thread *td; 99756dd3a61SPoul-Henning Kamp 9987818e0a5SKonstantin Belousov td = curthread; 9997818e0a5SKonstantin Belousov fpop = td->td_fpop; 10003979450bSKonstantin Belousov error = devfs_fp_check(fp, &dev, &dsw, &ref); 1001aac5167cSPoul-Henning Kamp if (error) 1002aac5167cSPoul-Henning Kamp return (error); 100356dd3a61SPoul-Henning Kamp error = dsw->d_kqfilter(dev, kn); 10047818e0a5SKonstantin Belousov td->td_fpop = fpop; 10053979450bSKonstantin Belousov dev_relthread(dev, ref); 100656dd3a61SPoul-Henning Kamp return (error); 100756dd3a61SPoul-Henning Kamp } 100856dd3a61SPoul-Henning Kamp 1009f8f61460SEd Schouten static inline int 10108dc9b4cfSEd Schouten devfs_prison_check(struct devfs_dirent *de, struct thread *td) 1011f8f61460SEd Schouten { 1012f8f61460SEd Schouten struct cdev_priv *cdp; 1013f8f61460SEd Schouten struct ucred *dcr; 10144dba07b2SMateusz Guzik struct proc *p; 10158dc9b4cfSEd Schouten int error; 1016f8f61460SEd Schouten 1017f8f61460SEd Schouten cdp = de->de_cdp; 1018f8f61460SEd Schouten if (cdp == NULL) 1019f8f61460SEd Schouten return (0); 1020f8f61460SEd Schouten dcr = cdp->cdp_c.si_cred; 1021f8f61460SEd Schouten if (dcr == NULL) 1022f8f61460SEd Schouten return (0); 1023f8f61460SEd Schouten 10248dc9b4cfSEd Schouten error = prison_check(td->td_ucred, dcr); 10258dc9b4cfSEd Schouten if (error == 0) 10268dc9b4cfSEd Schouten return (0); 10278dc9b4cfSEd Schouten /* We do, however, allow access to the controlling terminal */ 10284dba07b2SMateusz Guzik p = td->td_proc; 10294dba07b2SMateusz Guzik PROC_LOCK(p); 10304dba07b2SMateusz Guzik if (!(p->p_flag & P_CONTROLT)) { 10314dba07b2SMateusz Guzik PROC_UNLOCK(p); 10328dc9b4cfSEd Schouten return (error); 10334dba07b2SMateusz Guzik } 10344dba07b2SMateusz Guzik if (p->p_session->s_ttydp == cdp) 10354dba07b2SMateusz Guzik error = 0; 10364dba07b2SMateusz Guzik PROC_UNLOCK(p); 10378dc9b4cfSEd Schouten return (error); 1038f8f61460SEd Schouten } 1039f8f61460SEd Schouten 104056dd3a61SPoul-Henning Kamp static int 1041e7f9b744SKonstantin Belousov devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock) 10423f54a085SPoul-Henning Kamp { 1043c32d0a1dSPoul-Henning Kamp struct componentname *cnp; 1044c32d0a1dSPoul-Henning Kamp struct vnode *dvp, **vpp; 1045b40ce416SJulian Elischer struct thread *td; 1046c32d0a1dSPoul-Henning Kamp struct devfs_dirent *de, *dd; 10477e8766a9SPoul-Henning Kamp struct devfs_dirent **dde; 1048c32d0a1dSPoul-Henning Kamp struct devfs_mount *dmp; 104983342922SKonstantin Belousov struct mount *mp; 105089c9c53dSPoul-Henning Kamp struct cdev *cdev; 10519968a426SKonstantin Belousov int error, flags, nameiop, dvplocked; 1052c32d0a1dSPoul-Henning Kamp char specname[SPECNAMELEN + 1], *pname; 10533f54a085SPoul-Henning Kamp 1054b4a58fbfSMateusz Guzik td = curthread; 1055c32d0a1dSPoul-Henning Kamp cnp = ap->a_cnp; 1056c32d0a1dSPoul-Henning Kamp vpp = ap->a_vpp; 1057c32d0a1dSPoul-Henning Kamp dvp = ap->a_dvp; 1058c32d0a1dSPoul-Henning Kamp pname = cnp->cn_nameptr; 1059c32d0a1dSPoul-Henning Kamp flags = cnp->cn_flags; 1060c32d0a1dSPoul-Henning Kamp nameiop = cnp->cn_nameiop; 106183342922SKonstantin Belousov mp = dvp->v_mount; 106283342922SKonstantin Belousov dmp = VFSTODEVFS(mp); 1063c32d0a1dSPoul-Henning Kamp dd = dvp->v_data; 1064c32d0a1dSPoul-Henning Kamp *vpp = NULLVP; 1065c32d0a1dSPoul-Henning Kamp 10668eee3a3dSMaxime Henrion if ((flags & ISLASTCN) && nameiop == RENAME) 10673f54a085SPoul-Henning Kamp return (EOPNOTSUPP); 10683f54a085SPoul-Henning Kamp 1069c32d0a1dSPoul-Henning Kamp if (dvp->v_type != VDIR) 1070c32d0a1dSPoul-Henning Kamp return (ENOTDIR); 1071c32d0a1dSPoul-Henning Kamp 1072e6e370a7SJeff Roberson if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 1073c32d0a1dSPoul-Henning Kamp return (EIO); 1074c32d0a1dSPoul-Henning Kamp 10756a5abb1eSKyle Evans error = vn_dir_check_exec(dvp, cnp); 10766a5abb1eSKyle Evans if (error != 0) 1077c32d0a1dSPoul-Henning Kamp return (error); 1078c32d0a1dSPoul-Henning Kamp 1079c32d0a1dSPoul-Henning Kamp if (cnp->cn_namelen == 1 && *pname == '.') { 10808eee3a3dSMaxime Henrion if ((flags & ISLASTCN) && nameiop != LOOKUP) 1081c32d0a1dSPoul-Henning Kamp return (EINVAL); 1082c32d0a1dSPoul-Henning Kamp *vpp = dvp; 1083c32d0a1dSPoul-Henning Kamp VREF(dvp); 1084c32d0a1dSPoul-Henning Kamp return (0); 1085c32d0a1dSPoul-Henning Kamp } 1086c32d0a1dSPoul-Henning Kamp 1087c32d0a1dSPoul-Henning Kamp if (flags & ISDOTDOT) { 10888eee3a3dSMaxime Henrion if ((flags & ISLASTCN) && nameiop != LOOKUP) 1089c32d0a1dSPoul-Henning Kamp return (EINVAL); 1090f40645c8SJaakko Heinonen de = devfs_parent_dirent(dd); 1091f40645c8SJaakko Heinonen if (de == NULL) 1092f40645c8SJaakko Heinonen return (ENOENT); 10939968a426SKonstantin Belousov dvplocked = VOP_ISLOCKED(dvp); 1094b249ce48SMateusz Guzik VOP_UNLOCK(dvp); 109583342922SKonstantin Belousov error = devfs_allocv(de, mp, cnp->cn_lkflags & LK_TYPE_MASK, 109683342922SKonstantin Belousov vpp); 1097e7f9b744SKonstantin Belousov *dm_unlock = 0; 10989968a426SKonstantin Belousov vn_lock(dvp, dvplocked | LK_RETRY); 1099c32d0a1dSPoul-Henning Kamp return (error); 1100c32d0a1dSPoul-Henning Kamp } 1101c32d0a1dSPoul-Henning Kamp 1102c32d0a1dSPoul-Henning Kamp dd = dvp->v_data; 110364040d39SJaakko Heinonen de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen, 0); 1104e606a3c6SPoul-Henning Kamp while (de == NULL) { /* While(...) so we can use break */ 1105c32d0a1dSPoul-Henning Kamp 11065a9300c4SPoul-Henning Kamp if (nameiop == DELETE) 1107e606a3c6SPoul-Henning Kamp return (ENOENT); 11085a9300c4SPoul-Henning Kamp 1109c32d0a1dSPoul-Henning Kamp /* 1110c32d0a1dSPoul-Henning Kamp * OK, we didn't have an entry for the name we were asked for 1111c32d0a1dSPoul-Henning Kamp * so we try to see if anybody can create it on demand. 1112c32d0a1dSPoul-Henning Kamp */ 11136adc5230SJaakko Heinonen pname = devfs_fqpn(specname, dmp, dd, cnp); 11145a9300c4SPoul-Henning Kamp if (pname == NULL) 1115e606a3c6SPoul-Henning Kamp break; 1116c32d0a1dSPoul-Henning Kamp 1117f3732fd1SPoul-Henning Kamp cdev = NULL; 1118de10ffa5SKonstantin Belousov DEVFS_DMP_HOLD(dmp); 1119de10ffa5SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 1120e606a3c6SPoul-Henning Kamp EVENTHANDLER_INVOKE(dev_clone, 1121e606a3c6SPoul-Henning Kamp td->td_ucred, pname, strlen(pname), &cdev); 11220f6bb099SJaakko Heinonen 11230f6bb099SJaakko Heinonen if (cdev == NULL) 1124de10ffa5SKonstantin Belousov sx_xlock(&dmp->dm_lock); 11250f6bb099SJaakko Heinonen else if (devfs_populate_vp(dvp) != 0) { 11260f6bb099SJaakko Heinonen *dm_unlock = 0; 11270f6bb099SJaakko Heinonen sx_xlock(&dmp->dm_lock); 11280f6bb099SJaakko Heinonen if (DEVFS_DMP_DROP(dmp)) { 11290f6bb099SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 11300f6bb099SJaakko Heinonen devfs_unmount_final(dmp); 11310f6bb099SJaakko Heinonen } else 11320f6bb099SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 11330f6bb099SJaakko Heinonen dev_rel(cdev); 11340f6bb099SJaakko Heinonen return (ENOENT); 11350f6bb099SJaakko Heinonen } 1136de10ffa5SKonstantin Belousov if (DEVFS_DMP_DROP(dmp)) { 1137de10ffa5SKonstantin Belousov *dm_unlock = 0; 1138de10ffa5SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 1139de10ffa5SKonstantin Belousov devfs_unmount_final(dmp); 114096835d61SJaakko Heinonen if (cdev != NULL) 114196835d61SJaakko Heinonen dev_rel(cdev); 1142de10ffa5SKonstantin Belousov return (ENOENT); 1143de10ffa5SKonstantin Belousov } 11440f6bb099SJaakko Heinonen 1145f3732fd1SPoul-Henning Kamp if (cdev == NULL) 1146e606a3c6SPoul-Henning Kamp break; 1147c32d0a1dSPoul-Henning Kamp 1148e606a3c6SPoul-Henning Kamp dev_lock(); 114905427aafSKonstantin Belousov dde = &cdev2priv(cdev)->cdp_dirents[dmp->dm_idx]; 1150e606a3c6SPoul-Henning Kamp if (dde != NULL && *dde != NULL) 11517e8766a9SPoul-Henning Kamp de = *dde; 1152e606a3c6SPoul-Henning Kamp dev_unlock(); 1153e606a3c6SPoul-Henning Kamp dev_rel(cdev); 1154e606a3c6SPoul-Henning Kamp break; 1155e606a3c6SPoul-Henning Kamp } 1156c32d0a1dSPoul-Henning Kamp 1157e606a3c6SPoul-Henning Kamp if (de == NULL || de->de_flags & DE_WHITEOUT) { 1158c32d0a1dSPoul-Henning Kamp if ((nameiop == CREATE || nameiop == RENAME) && 1159c32d0a1dSPoul-Henning Kamp (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 1160c32d0a1dSPoul-Henning Kamp return (EJUSTRETURN); 1161c32d0a1dSPoul-Henning Kamp } 1162c32d0a1dSPoul-Henning Kamp return (ENOENT); 1163e606a3c6SPoul-Henning Kamp } 1164c32d0a1dSPoul-Henning Kamp 11658dc9b4cfSEd Schouten if (devfs_prison_check(de, td)) 1166f8f61460SEd Schouten return (ENOENT); 1167f8f61460SEd Schouten 1168c32d0a1dSPoul-Henning Kamp if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 1169b40ce416SJulian Elischer error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1170c32d0a1dSPoul-Henning Kamp if (error) 1171c32d0a1dSPoul-Henning Kamp return (error); 1172c32d0a1dSPoul-Henning Kamp if (*vpp == dvp) { 1173c32d0a1dSPoul-Henning Kamp VREF(dvp); 1174c32d0a1dSPoul-Henning Kamp *vpp = dvp; 1175c32d0a1dSPoul-Henning Kamp return (0); 1176c32d0a1dSPoul-Henning Kamp } 1177c32d0a1dSPoul-Henning Kamp } 117883342922SKonstantin Belousov error = devfs_allocv(de, mp, cnp->cn_lkflags & LK_TYPE_MASK, vpp); 1179e7f9b744SKonstantin Belousov *dm_unlock = 0; 1180c32d0a1dSPoul-Henning Kamp return (error); 1181c32d0a1dSPoul-Henning Kamp } 1182c32d0a1dSPoul-Henning Kamp 118393bcdfe2SPoul-Henning Kamp static int 118493bcdfe2SPoul-Henning Kamp devfs_lookup(struct vop_lookup_args *ap) 118593bcdfe2SPoul-Henning Kamp { 118693bcdfe2SPoul-Henning Kamp int j; 118793bcdfe2SPoul-Henning Kamp struct devfs_mount *dmp; 1188e7f9b744SKonstantin Belousov int dm_unlock; 118993bcdfe2SPoul-Henning Kamp 11900f6bb099SJaakko Heinonen if (devfs_populate_vp(ap->a_dvp) != 0) 11910f6bb099SJaakko Heinonen return (ENOTDIR); 11920f6bb099SJaakko Heinonen 119393bcdfe2SPoul-Henning Kamp dmp = VFSTODEVFS(ap->a_dvp->v_mount); 1194e7f9b744SKonstantin Belousov dm_unlock = 1; 1195e7f9b744SKonstantin Belousov j = devfs_lookupx(ap, &dm_unlock); 1196e7f9b744SKonstantin Belousov if (dm_unlock == 1) 1197e606a3c6SPoul-Henning Kamp sx_xunlock(&dmp->dm_lock); 119893bcdfe2SPoul-Henning Kamp return (j); 119993bcdfe2SPoul-Henning Kamp } 120093bcdfe2SPoul-Henning Kamp 12015a9300c4SPoul-Henning Kamp static int 12025a9300c4SPoul-Henning Kamp devfs_mknod(struct vop_mknod_args *ap) 12035a9300c4SPoul-Henning Kamp { 12045a9300c4SPoul-Henning Kamp struct componentname *cnp; 12055a9300c4SPoul-Henning Kamp struct vnode *dvp, **vpp; 12065a9300c4SPoul-Henning Kamp struct devfs_dirent *dd, *de; 12075a9300c4SPoul-Henning Kamp struct devfs_mount *dmp; 12085a9300c4SPoul-Henning Kamp int error; 12095a9300c4SPoul-Henning Kamp 121002a4be3fSSimon L. B. Nielsen /* 121102a4be3fSSimon L. B. Nielsen * The only type of node we should be creating here is a 121202a4be3fSSimon L. B. Nielsen * character device, for anything else return EOPNOTSUPP. 121302a4be3fSSimon L. B. Nielsen */ 121402a4be3fSSimon L. B. Nielsen if (ap->a_vap->va_type != VCHR) 121502a4be3fSSimon L. B. Nielsen return (EOPNOTSUPP); 12165a9300c4SPoul-Henning Kamp dvp = ap->a_dvp; 12175a9300c4SPoul-Henning Kamp dmp = VFSTODEVFS(dvp->v_mount); 12185a9300c4SPoul-Henning Kamp 12195a9300c4SPoul-Henning Kamp cnp = ap->a_cnp; 12205a9300c4SPoul-Henning Kamp vpp = ap->a_vpp; 12215a9300c4SPoul-Henning Kamp dd = dvp->v_data; 12225a9300c4SPoul-Henning Kamp 12235a9300c4SPoul-Henning Kamp error = ENOENT; 1224e7f9b744SKonstantin Belousov sx_xlock(&dmp->dm_lock); 12255a9300c4SPoul-Henning Kamp TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 12265a9300c4SPoul-Henning Kamp if (cnp->cn_namelen != de->de_dirent->d_namlen) 12275a9300c4SPoul-Henning Kamp continue; 1228a57a934aSKonstantin Belousov if (de->de_dirent->d_type == DT_CHR && 1229a57a934aSKonstantin Belousov (de->de_cdp->cdp_flags & CDP_ACTIVE) == 0) 1230a57a934aSKonstantin Belousov continue; 12315a9300c4SPoul-Henning Kamp if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 12325a9300c4SPoul-Henning Kamp de->de_dirent->d_namlen) != 0) 12335a9300c4SPoul-Henning Kamp continue; 12345a9300c4SPoul-Henning Kamp if (de->de_flags & DE_WHITEOUT) 12355a9300c4SPoul-Henning Kamp break; 12365a9300c4SPoul-Henning Kamp goto notfound; 12375a9300c4SPoul-Henning Kamp } 12385a9300c4SPoul-Henning Kamp if (de == NULL) 12395a9300c4SPoul-Henning Kamp goto notfound; 12405a9300c4SPoul-Henning Kamp de->de_flags &= ~DE_WHITEOUT; 12419968a426SKonstantin Belousov error = devfs_allocv(de, dvp->v_mount, LK_EXCLUSIVE, vpp); 1242e7f9b744SKonstantin Belousov return (error); 12435a9300c4SPoul-Henning Kamp notfound: 1244e606a3c6SPoul-Henning Kamp sx_xunlock(&dmp->dm_lock); 12455a9300c4SPoul-Henning Kamp return (error); 12465a9300c4SPoul-Henning Kamp } 12475a9300c4SPoul-Henning Kamp 1248ff7c5a48SPoul-Henning Kamp /* ARGSUSED */ 1249ff7c5a48SPoul-Henning Kamp static int 125021806f30SPoul-Henning Kamp devfs_open(struct vop_open_args *ap) 1251ff7c5a48SPoul-Henning Kamp { 1252ff7c5a48SPoul-Henning Kamp struct thread *td = ap->a_td; 1253ff7c5a48SPoul-Henning Kamp struct vnode *vp = ap->a_vp; 1254ff7c5a48SPoul-Henning Kamp struct cdev *dev = vp->v_rdev; 12559e223287SKonstantin Belousov struct file *fp = ap->a_fp; 12563979450bSKonstantin Belousov int error, ref, vlocked; 1257ff7c5a48SPoul-Henning Kamp struct cdevsw *dsw; 12587818e0a5SKonstantin Belousov struct file *fpop; 1259ff7c5a48SPoul-Henning Kamp 1260ff7c5a48SPoul-Henning Kamp if (vp->v_type == VBLK) 1261ff7c5a48SPoul-Henning Kamp return (ENXIO); 1262ff7c5a48SPoul-Henning Kamp 1263ff7c5a48SPoul-Henning Kamp if (dev == NULL) 1264ff7c5a48SPoul-Henning Kamp return (ENXIO); 1265ff7c5a48SPoul-Henning Kamp 1266ff7c5a48SPoul-Henning Kamp /* Make this field valid before any I/O in d_open. */ 1267ff7c5a48SPoul-Henning Kamp if (dev->si_iosize_max == 0) 1268ff7c5a48SPoul-Henning Kamp dev->si_iosize_max = DFLTPHYS; 1269ff7c5a48SPoul-Henning Kamp 12703979450bSKonstantin Belousov dsw = dev_refthread(dev, &ref); 1271ff7c5a48SPoul-Henning Kamp if (dsw == NULL) 1272ff7c5a48SPoul-Henning Kamp return (ENXIO); 12731fef78c3SKonstantin Belousov if (fp == NULL && dsw->d_fdopen != NULL) { 12741fef78c3SKonstantin Belousov dev_relthread(dev, ref); 12751fef78c3SKonstantin Belousov return (ENXIO); 12761fef78c3SKonstantin Belousov } 1277ff7c5a48SPoul-Henning Kamp 12783b444436SMateusz Guzik if (vp->v_type == VCHR) 12793b444436SMateusz Guzik devfs_usecount_add(vp); 12803b444436SMateusz Guzik 12819968a426SKonstantin Belousov vlocked = VOP_ISLOCKED(vp); 1282b249ce48SMateusz Guzik VOP_UNLOCK(vp); 1283ff7c5a48SPoul-Henning Kamp 12847818e0a5SKonstantin Belousov fpop = td->td_fpop; 128582f4d640SKonstantin Belousov td->td_fpop = fp; 12860e9bd89dSKonstantin Belousov if (fp != NULL) { 128782f4d640SKonstantin Belousov fp->f_data = dev; 12880e9bd89dSKonstantin Belousov fp->f_vnode = vp; 12890e9bd89dSKonstantin Belousov } 1290ff7c5a48SPoul-Henning Kamp if (dsw->d_fdopen != NULL) 12919e223287SKonstantin Belousov error = dsw->d_fdopen(dev, ap->a_mode, td, fp); 1292ff7c5a48SPoul-Henning Kamp else 1293ff7c5a48SPoul-Henning Kamp error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td); 1294d52aff3cSKonstantin Belousov /* Clean up any cdevpriv upon error. */ 129507da61a6SHans Petter Selasky if (error != 0) 129607da61a6SHans Petter Selasky devfs_clear_cdevpriv(); 12977818e0a5SKonstantin Belousov td->td_fpop = fpop; 1298ff7c5a48SPoul-Henning Kamp 12999968a426SKonstantin Belousov vn_lock(vp, vlocked | LK_RETRY); 13003b444436SMateusz Guzik if (error != 0 && vp->v_type == VCHR) 13013b444436SMateusz Guzik devfs_usecount_sub(vp); 13023b444436SMateusz Guzik 13033979450bSKonstantin Belousov dev_relthread(dev, ref); 13042ca49983SKonstantin Belousov if (error != 0) { 13052ca49983SKonstantin Belousov if (error == ERESTART) 13062ca49983SKonstantin Belousov error = EINTR; 1307ff7c5a48SPoul-Henning Kamp return (error); 13082ca49983SKonstantin Belousov } 1309ff7c5a48SPoul-Henning Kamp 13102a9e0c32SPoul-Henning Kamp #if 0 /* /dev/console */ 13119968a426SKonstantin Belousov KASSERT(fp != NULL, ("Could not vnode bypass device on NULL fp")); 13122a9e0c32SPoul-Henning Kamp #else 13139e223287SKonstantin Belousov if (fp == NULL) 13142a9e0c32SPoul-Henning Kamp return (error); 13152a9e0c32SPoul-Henning Kamp #endif 131634d1dcf0SEd Schouten if (fp->f_ops == &badfileops) 1317397c19d1SJeff Roberson finit(fp, fp->f_flag, DTYPE_VNODE, dev, &devfs_ops_f); 1318ff7c5a48SPoul-Henning Kamp return (error); 1319ff7c5a48SPoul-Henning Kamp } 1320ff7c5a48SPoul-Henning Kamp 13212ab80ed8SDima Dorfman static int 132221806f30SPoul-Henning Kamp devfs_pathconf(struct vop_pathconf_args *ap) 13232ab80ed8SDima Dorfman { 13242ab80ed8SDima Dorfman 13252ab80ed8SDima Dorfman switch (ap->a_name) { 1326418e6212SJohn Baldwin case _PC_FILESIZEBITS: 1327418e6212SJohn Baldwin *ap->a_retval = 64; 1328418e6212SJohn Baldwin return (0); 1329599afe53SJohn Baldwin case _PC_NAME_MAX: 1330599afe53SJohn Baldwin *ap->a_retval = NAME_MAX; 1331599afe53SJohn Baldwin return (0); 1332599afe53SJohn Baldwin case _PC_LINK_MAX: 1333f6e25ec7SJohn Baldwin *ap->a_retval = INT_MAX; 1334599afe53SJohn Baldwin return (0); 1335418e6212SJohn Baldwin case _PC_SYMLINK_MAX: 1336418e6212SJohn Baldwin *ap->a_retval = MAXPATHLEN; 1337418e6212SJohn Baldwin return (0); 1338e1d15b89SJohn Baldwin case _PC_MAX_CANON: 1339e1d15b89SJohn Baldwin if (ap->a_vp->v_vflag & VV_ISTTY) { 1340e1d15b89SJohn Baldwin *ap->a_retval = MAX_CANON; 1341e1d15b89SJohn Baldwin return (0); 1342e1d15b89SJohn Baldwin } 1343e1d15b89SJohn Baldwin return (EINVAL); 1344e1d15b89SJohn Baldwin case _PC_MAX_INPUT: 1345e1d15b89SJohn Baldwin if (ap->a_vp->v_vflag & VV_ISTTY) { 1346e1d15b89SJohn Baldwin *ap->a_retval = MAX_INPUT; 1347e1d15b89SJohn Baldwin return (0); 1348e1d15b89SJohn Baldwin } 1349e1d15b89SJohn Baldwin return (EINVAL); 1350e1d15b89SJohn Baldwin case _PC_VDISABLE: 1351e1d15b89SJohn Baldwin if (ap->a_vp->v_vflag & VV_ISTTY) { 1352e1d15b89SJohn Baldwin *ap->a_retval = _POSIX_VDISABLE; 1353e1d15b89SJohn Baldwin return (0); 1354e1d15b89SJohn Baldwin } 1355e1d15b89SJohn Baldwin return (EINVAL); 1356e6a5564eSRobert Watson case _PC_MAC_PRESENT: 135767d722edSRobert Watson #ifdef MAC 135867d722edSRobert Watson /* 135967d722edSRobert Watson * If MAC is enabled, devfs automatically supports 13608ea3cedaSGordon Bergling * trivial non-persistent label storage. 136167d722edSRobert Watson */ 136267d722edSRobert Watson *ap->a_retval = 1; 136367d722edSRobert Watson #else 136467d722edSRobert Watson *ap->a_retval = 0; 1365e6a5564eSRobert Watson #endif 136667d722edSRobert Watson return (0); 1367599afe53SJohn Baldwin case _PC_CHOWN_RESTRICTED: 1368599afe53SJohn Baldwin *ap->a_retval = 1; 1369599afe53SJohn Baldwin return (0); 13702ab80ed8SDima Dorfman default: 13712ab80ed8SDima Dorfman return (vop_stdpathconf(ap)); 13722ab80ed8SDima Dorfman } 13732ab80ed8SDima Dorfman /* NOTREACHED */ 13742ab80ed8SDima Dorfman } 13752ab80ed8SDima Dorfman 1376ff7c5a48SPoul-Henning Kamp /* ARGSUSED */ 1377ff7c5a48SPoul-Henning Kamp static int 137856dd3a61SPoul-Henning Kamp devfs_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td) 137956dd3a61SPoul-Henning Kamp { 138056dd3a61SPoul-Henning Kamp struct cdev *dev; 138156dd3a61SPoul-Henning Kamp struct cdevsw *dsw; 13823979450bSKonstantin Belousov int error, ref; 13837818e0a5SKonstantin Belousov struct file *fpop; 138456dd3a61SPoul-Henning Kamp 13857818e0a5SKonstantin Belousov fpop = td->td_fpop; 13863979450bSKonstantin Belousov error = devfs_fp_check(fp, &dev, &dsw, &ref); 1387f12aa60cSKonstantin Belousov if (error != 0) { 1388f12aa60cSKonstantin Belousov error = vnops.fo_poll(fp, events, cred, td); 1389f12aa60cSKonstantin Belousov return (error); 1390f12aa60cSKonstantin Belousov } 139156dd3a61SPoul-Henning Kamp error = dsw->d_poll(dev, events, td); 13927818e0a5SKonstantin Belousov td->td_fpop = fpop; 13933979450bSKonstantin Belousov dev_relthread(dev, ref); 139456dd3a61SPoul-Henning Kamp return(error); 139556dd3a61SPoul-Henning Kamp } 139656dd3a61SPoul-Henning Kamp 1397ff7c5a48SPoul-Henning Kamp /* 1398ff7c5a48SPoul-Henning Kamp * Print out the contents of a special device vnode. 1399ff7c5a48SPoul-Henning Kamp */ 1400ff7c5a48SPoul-Henning Kamp static int 140121806f30SPoul-Henning Kamp devfs_print(struct vop_print_args *ap) 1402ff7c5a48SPoul-Henning Kamp { 1403ff7c5a48SPoul-Henning Kamp 1404ff7c5a48SPoul-Henning Kamp printf("\tdev %s\n", devtoname(ap->a_vp->v_rdev)); 1405ff7c5a48SPoul-Henning Kamp return (0); 1406ff7c5a48SPoul-Henning Kamp } 1407ff7c5a48SPoul-Henning Kamp 14083f54a085SPoul-Henning Kamp static int 140964548150SKonstantin Belousov devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, 141064548150SKonstantin Belousov int flags, struct thread *td) 141156dd3a61SPoul-Henning Kamp { 141256dd3a61SPoul-Henning Kamp struct cdev *dev; 1413526d0bd5SKonstantin Belousov int ioflag, error, ref; 1414526d0bd5SKonstantin Belousov ssize_t resid; 141556dd3a61SPoul-Henning Kamp struct cdevsw *dsw; 14167818e0a5SKonstantin Belousov struct file *fpop; 141756dd3a61SPoul-Henning Kamp 1418bf3e483bSKonstantin Belousov if (uio->uio_resid > DEVFS_IOSIZE_MAX) 1419bf3e483bSKonstantin Belousov return (EINVAL); 14207818e0a5SKonstantin Belousov fpop = td->td_fpop; 14213979450bSKonstantin Belousov error = devfs_fp_check(fp, &dev, &dsw, &ref); 1422f12aa60cSKonstantin Belousov if (error != 0) { 1423f12aa60cSKonstantin Belousov error = vnops.fo_read(fp, uio, cred, flags, td); 1424aac5167cSPoul-Henning Kamp return (error); 1425f12aa60cSKonstantin Belousov } 142656dd3a61SPoul-Henning Kamp resid = uio->uio_resid; 142750a36c11SPoul-Henning Kamp ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT); 142850a36c11SPoul-Henning Kamp if (ioflag & O_DIRECT) 142956dd3a61SPoul-Henning Kamp ioflag |= IO_DIRECT; 143056dd3a61SPoul-Henning Kamp 1431c5c1199cSKonstantin Belousov foffset_lock_uio(fp, uio, flags | FOF_NOLOCK); 143256dd3a61SPoul-Henning Kamp error = dsw->d_read(dev, uio, ioflag); 1433bda2eb9aSKonstantin Belousov if (uio->uio_resid != resid || (error == 0 && resid != 0)) 1434bda2eb9aSKonstantin Belousov devfs_timestamp(&dev->si_atime); 14357818e0a5SKonstantin Belousov td->td_fpop = fpop; 14363979450bSKonstantin Belousov dev_relthread(dev, ref); 143756dd3a61SPoul-Henning Kamp 1438f2706588SThomas Munro foffset_unlock_uio(fp, uio, flags | FOF_NOLOCK | FOF_NEXTOFF_R); 143956dd3a61SPoul-Henning Kamp return (error); 144056dd3a61SPoul-Henning Kamp } 144156dd3a61SPoul-Henning Kamp 144256dd3a61SPoul-Henning Kamp static int 144321806f30SPoul-Henning Kamp devfs_readdir(struct vop_readdir_args *ap) 14443f54a085SPoul-Henning Kamp { 1445749e1537SPoul-Henning Kamp int error; 1446749e1537SPoul-Henning Kamp struct uio *uio; 14473f54a085SPoul-Henning Kamp struct dirent *dp; 1448a481b90bSPoul-Henning Kamp struct devfs_dirent *dd; 14493f54a085SPoul-Henning Kamp struct devfs_dirent *de; 1450a481b90bSPoul-Henning Kamp struct devfs_mount *dmp; 14517956d34bSBjoern A. Zeeb off_t off; 145216e35dccSDoug White int *tmp_ncookies = NULL; 14533f54a085SPoul-Henning Kamp 14543f54a085SPoul-Henning Kamp if (ap->a_vp->v_type != VDIR) 14553f54a085SPoul-Henning Kamp return (ENOTDIR); 14563f54a085SPoul-Henning Kamp 1457749e1537SPoul-Henning Kamp uio = ap->a_uio; 1458749e1537SPoul-Henning Kamp if (uio->uio_offset < 0) 1459749e1537SPoul-Henning Kamp return (EINVAL); 1460749e1537SPoul-Henning Kamp 146116e35dccSDoug White /* 146216e35dccSDoug White * XXX: This is a temporary hack to get around this filesystem not 146316e35dccSDoug White * supporting cookies. We store the location of the ncookies pointer 146416e35dccSDoug White * in a temporary variable before calling vfs_subr.c:vfs_read_dirent() 146516e35dccSDoug White * and set the number of cookies to 0. We then set the pointer to 146616e35dccSDoug White * NULL so that vfs_read_dirent doesn't try to call realloc() on 146716e35dccSDoug White * ap->a_cookies. Later in this function, we restore the ap->a_ncookies 146816e35dccSDoug White * pointer to its original location before returning to the caller. 146916e35dccSDoug White */ 147016e35dccSDoug White if (ap->a_ncookies != NULL) { 147116e35dccSDoug White tmp_ncookies = ap->a_ncookies; 147216e35dccSDoug White *ap->a_ncookies = 0; 147316e35dccSDoug White ap->a_ncookies = NULL; 147416e35dccSDoug White } 147516e35dccSDoug White 1476a481b90bSPoul-Henning Kamp dmp = VFSTODEVFS(ap->a_vp->v_mount); 14770f6bb099SJaakko Heinonen if (devfs_populate_vp(ap->a_vp) != 0) { 1478828d6d12SKonstantin Belousov if (tmp_ncookies != NULL) 1479828d6d12SKonstantin Belousov ap->a_ncookies = tmp_ncookies; 1480828d6d12SKonstantin Belousov return (EIO); 1481828d6d12SKonstantin Belousov } 14823f54a085SPoul-Henning Kamp error = 0; 1483a481b90bSPoul-Henning Kamp de = ap->a_vp->v_data; 14843f54a085SPoul-Henning Kamp off = 0; 14855a9300c4SPoul-Henning Kamp TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 1486e606a3c6SPoul-Henning Kamp KASSERT(dd->de_cdp != (void *)0xdeadc0de, ("%s %d\n", __func__, __LINE__)); 148764040d39SJaakko Heinonen if (dd->de_flags & (DE_COVERED | DE_WHITEOUT)) 14885a9300c4SPoul-Henning Kamp continue; 14898dc9b4cfSEd Schouten if (devfs_prison_check(dd, uio->uio_td)) 1490f8f61460SEd Schouten continue; 1491a481b90bSPoul-Henning Kamp if (dd->de_dirent->d_type == DT_DIR) 1492a481b90bSPoul-Henning Kamp de = dd->de_dir; 1493a481b90bSPoul-Henning Kamp else 1494a481b90bSPoul-Henning Kamp de = dd; 1495a481b90bSPoul-Henning Kamp dp = dd->de_dirent; 149669921123SKonstantin Belousov MPASS(dp->d_reclen == GENERIC_DIRSIZ(dp)); 1497749e1537SPoul-Henning Kamp if (dp->d_reclen > uio->uio_resid) 14983f54a085SPoul-Henning Kamp break; 1499749e1537SPoul-Henning Kamp dp->d_fileno = de->de_inode; 15001c4ca778SKonstantin Belousov /* NOTE: d_off is the offset for the *next* entry. */ 15011c4ca778SKonstantin Belousov dp->d_off = off + dp->d_reclen; 1502749e1537SPoul-Henning Kamp if (off >= uio->uio_offset) { 150321806f30SPoul-Henning Kamp error = vfs_read_dirent(ap, dp, off); 1504749e1537SPoul-Henning Kamp if (error) 1505749e1537SPoul-Henning Kamp break; 1506749e1537SPoul-Henning Kamp } 15073f54a085SPoul-Henning Kamp off += dp->d_reclen; 15083f54a085SPoul-Henning Kamp } 1509e606a3c6SPoul-Henning Kamp sx_xunlock(&dmp->dm_lock); 15103f54a085SPoul-Henning Kamp uio->uio_offset = off; 151116e35dccSDoug White 151216e35dccSDoug White /* 151316e35dccSDoug White * Restore ap->a_ncookies if it wasn't originally NULL in the first 151416e35dccSDoug White * place. 151516e35dccSDoug White */ 151616e35dccSDoug White if (tmp_ncookies != NULL) 151716e35dccSDoug White ap->a_ncookies = tmp_ncookies; 151816e35dccSDoug White 15193f54a085SPoul-Henning Kamp return (error); 15203f54a085SPoul-Henning Kamp } 15213f54a085SPoul-Henning Kamp 15223f54a085SPoul-Henning Kamp static int 152321806f30SPoul-Henning Kamp devfs_readlink(struct vop_readlink_args *ap) 15243f54a085SPoul-Henning Kamp { 15253f54a085SPoul-Henning Kamp struct devfs_dirent *de; 15263f54a085SPoul-Henning Kamp 15273f54a085SPoul-Henning Kamp de = ap->a_vp->v_data; 1528214c8ff0SPoul-Henning Kamp return (uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio)); 15293f54a085SPoul-Henning Kamp } 15303f54a085SPoul-Henning Kamp 15313b444436SMateusz Guzik static void 15323b444436SMateusz Guzik devfs_reclaiml(struct vnode *vp) 15333b444436SMateusz Guzik { 15343b444436SMateusz Guzik struct devfs_dirent *de; 15353b444436SMateusz Guzik 15363b444436SMateusz Guzik mtx_assert(&devfs_de_interlock, MA_OWNED); 15373b444436SMateusz Guzik de = vp->v_data; 15383b444436SMateusz Guzik if (de != NULL) { 15393b444436SMateusz Guzik MPASS(de->de_usecount == 0); 15403b444436SMateusz Guzik de->de_vnode = NULL; 15413b444436SMateusz Guzik vp->v_data = NULL; 15423b444436SMateusz Guzik } 15433b444436SMateusz Guzik } 15443b444436SMateusz Guzik 15453f54a085SPoul-Henning Kamp static int 154621806f30SPoul-Henning Kamp devfs_reclaim(struct vop_reclaim_args *ap) 15473f54a085SPoul-Henning Kamp { 15482d5bba3aSKonstantin Belousov struct vnode *vp; 15493f54a085SPoul-Henning Kamp 15502d5bba3aSKonstantin Belousov vp = ap->a_vp; 155156eeb277SStephan Uphoff mtx_lock(&devfs_de_interlock); 15523b444436SMateusz Guzik devfs_reclaiml(vp); 155356eeb277SStephan Uphoff mtx_unlock(&devfs_de_interlock); 15542d5bba3aSKonstantin Belousov return (0); 15552d5bba3aSKonstantin Belousov } 15562d5bba3aSKonstantin Belousov 15572d5bba3aSKonstantin Belousov static int 15582d5bba3aSKonstantin Belousov devfs_reclaim_vchr(struct vop_reclaim_args *ap) 15592d5bba3aSKonstantin Belousov { 15602d5bba3aSKonstantin Belousov struct vnode *vp; 15612d5bba3aSKonstantin Belousov struct cdev *dev; 15622d5bba3aSKonstantin Belousov 15632d5bba3aSKonstantin Belousov vp = ap->a_vp; 15642d5bba3aSKonstantin Belousov MPASS(vp->v_type == VCHR); 15652d5bba3aSKonstantin Belousov 15663b444436SMateusz Guzik mtx_lock(&devfs_de_interlock); 1567314464f4SJohn Baldwin VI_LOCK(vp); 15683b444436SMateusz Guzik devfs_usecount_subl(vp); 15693b444436SMateusz Guzik devfs_reclaiml(vp); 15703b444436SMateusz Guzik mtx_unlock(&devfs_de_interlock); 15711663075cSKonstantin Belousov dev_lock(); 1572aa2f6ddcSPoul-Henning Kamp dev = vp->v_rdev; 1573aa2f6ddcSPoul-Henning Kamp vp->v_rdev = NULL; 1574aa2f6ddcSPoul-Henning Kamp dev_unlock(); 1575314464f4SJohn Baldwin VI_UNLOCK(vp); 15762d5bba3aSKonstantin Belousov if (dev != NULL) 1577aa2f6ddcSPoul-Henning Kamp dev_rel(dev); 15783f54a085SPoul-Henning Kamp return (0); 15793f54a085SPoul-Henning Kamp } 15803f54a085SPoul-Henning Kamp 15813f54a085SPoul-Henning Kamp static int 158221806f30SPoul-Henning Kamp devfs_remove(struct vop_remove_args *ap) 15833f54a085SPoul-Henning Kamp { 158489d10571SJaakko Heinonen struct vnode *dvp = ap->a_dvp; 15853f54a085SPoul-Henning Kamp struct vnode *vp = ap->a_vp; 1586a481b90bSPoul-Henning Kamp struct devfs_dirent *dd; 158764040d39SJaakko Heinonen struct devfs_dirent *de, *de_covered; 158893bcdfe2SPoul-Henning Kamp struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 15893f54a085SPoul-Henning Kamp 159089d10571SJaakko Heinonen ASSERT_VOP_ELOCKED(dvp, "devfs_remove"); 159189d10571SJaakko Heinonen ASSERT_VOP_ELOCKED(vp, "devfs_remove"); 159289d10571SJaakko Heinonen 1593e606a3c6SPoul-Henning Kamp sx_xlock(&dmp->dm_lock); 15943f54a085SPoul-Henning Kamp dd = ap->a_dvp->v_data; 15953f54a085SPoul-Henning Kamp de = vp->v_data; 15963b72f38bSPoul-Henning Kamp if (de->de_cdp == NULL) { 159740739c02SPoul-Henning Kamp TAILQ_REMOVE(&dd->de_dlist, de, de_list); 159864040d39SJaakko Heinonen if (de->de_dirent->d_type == DT_LNK) { 159964040d39SJaakko Heinonen de_covered = devfs_find(dd, de->de_dirent->d_name, 160064040d39SJaakko Heinonen de->de_dirent->d_namlen, 0); 160164040d39SJaakko Heinonen if (de_covered != NULL) 160264040d39SJaakko Heinonen de_covered->de_flags &= ~DE_COVERED; 160364040d39SJaakko Heinonen } 160489d10571SJaakko Heinonen /* We need to unlock dvp because devfs_delete() may lock it. */ 1605b249ce48SMateusz Guzik VOP_UNLOCK(vp); 160689d10571SJaakko Heinonen if (dvp != vp) 1607b249ce48SMateusz Guzik VOP_UNLOCK(dvp); 160889d10571SJaakko Heinonen devfs_delete(dmp, de, 0); 160989d10571SJaakko Heinonen sx_xunlock(&dmp->dm_lock); 161089d10571SJaakko Heinonen if (dvp != vp) 161189d10571SJaakko Heinonen vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 161289d10571SJaakko Heinonen vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 161340739c02SPoul-Henning Kamp } else { 16145a9300c4SPoul-Henning Kamp de->de_flags |= DE_WHITEOUT; 1615e606a3c6SPoul-Henning Kamp sx_xunlock(&dmp->dm_lock); 161689d10571SJaakko Heinonen } 16173f54a085SPoul-Henning Kamp return (0); 16183f54a085SPoul-Henning Kamp } 16193f54a085SPoul-Henning Kamp 16203f54a085SPoul-Henning Kamp /* 16213f54a085SPoul-Henning Kamp * Revoke is called on a tty when a terminal session ends. The vnode 16223f54a085SPoul-Henning Kamp * is orphaned by setting v_op to deadfs so we need to let go of it 16233f54a085SPoul-Henning Kamp * as well so that we create a new one next time around. 1624e606a3c6SPoul-Henning Kamp * 16253f54a085SPoul-Henning Kamp */ 16263f54a085SPoul-Henning Kamp static int 162721806f30SPoul-Henning Kamp devfs_revoke(struct vop_revoke_args *ap) 16283f54a085SPoul-Henning Kamp { 1629e606a3c6SPoul-Henning Kamp struct vnode *vp = ap->a_vp, *vp2; 163049b7607eSPoul-Henning Kamp struct cdev *dev; 1631e606a3c6SPoul-Henning Kamp struct cdev_priv *cdp; 1632aa2f6ddcSPoul-Henning Kamp struct devfs_dirent *de; 1633f9c13ab8SMateusz Guzik enum vgetstate vs; 1634b114da42SPedro F. Giffuni u_int i; 16353f54a085SPoul-Henning Kamp 163649b7607eSPoul-Henning Kamp KASSERT((ap->a_flags & REVOKEALL) != 0, ("devfs_revoke !REVOKEALL")); 163749b7607eSPoul-Henning Kamp 163849b7607eSPoul-Henning Kamp dev = vp->v_rdev; 163905427aafSKonstantin Belousov cdp = cdev2priv(dev); 1640828d6d12SKonstantin Belousov 1641828d6d12SKonstantin Belousov dev_lock(); 1642828d6d12SKonstantin Belousov cdp->cdp_inuse++; 1643828d6d12SKonstantin Belousov dev_unlock(); 1644828d6d12SKonstantin Belousov 1645828d6d12SKonstantin Belousov vhold(vp); 1646828d6d12SKonstantin Belousov vgone(vp); 1647828d6d12SKonstantin Belousov vdrop(vp); 1648828d6d12SKonstantin Belousov 1649b249ce48SMateusz Guzik VOP_UNLOCK(vp); 1650828d6d12SKonstantin Belousov loop: 165149b7607eSPoul-Henning Kamp for (;;) { 165256eeb277SStephan Uphoff mtx_lock(&devfs_de_interlock); 165349b7607eSPoul-Henning Kamp dev_lock(); 1654e606a3c6SPoul-Henning Kamp vp2 = NULL; 1655e606a3c6SPoul-Henning Kamp for (i = 0; i <= cdp->cdp_maxdirent; i++) { 1656e606a3c6SPoul-Henning Kamp de = cdp->cdp_dirents[i]; 1657aa2f6ddcSPoul-Henning Kamp if (de == NULL) 1658e606a3c6SPoul-Henning Kamp continue; 165956eeb277SStephan Uphoff 1660e606a3c6SPoul-Henning Kamp vp2 = de->de_vnode; 1661e606a3c6SPoul-Henning Kamp if (vp2 != NULL) { 166256eeb277SStephan Uphoff dev_unlock(); 1663f9c13ab8SMateusz Guzik vs = vget_prep(vp2); 166456eeb277SStephan Uphoff mtx_unlock(&devfs_de_interlock); 1665f9c13ab8SMateusz Guzik if (vget_finish(vp2, LK_EXCLUSIVE, vs) != 0) 1666828d6d12SKonstantin Belousov goto loop; 1667828d6d12SKonstantin Belousov vhold(vp2); 1668e606a3c6SPoul-Henning Kamp vgone(vp2); 166923b77994SJeff Roberson vdrop(vp2); 1670828d6d12SKonstantin Belousov vput(vp2); 167156eeb277SStephan Uphoff break; 167256eeb277SStephan Uphoff } 167356eeb277SStephan Uphoff } 167456eeb277SStephan Uphoff if (vp2 != NULL) { 1675e606a3c6SPoul-Henning Kamp continue; 1676e606a3c6SPoul-Henning Kamp } 167756eeb277SStephan Uphoff dev_unlock(); 167856eeb277SStephan Uphoff mtx_unlock(&devfs_de_interlock); 1679e606a3c6SPoul-Henning Kamp break; 168049b7607eSPoul-Henning Kamp } 1681828d6d12SKonstantin Belousov dev_lock(); 1682828d6d12SKonstantin Belousov cdp->cdp_inuse--; 1683828d6d12SKonstantin Belousov if (!(cdp->cdp_flags & CDP_ACTIVE) && cdp->cdp_inuse == 0) { 168467864268SJason A. Harmening KASSERT((cdp->cdp_flags & CDP_ON_ACTIVE_LIST) != 0, 168567864268SJason A. Harmening ("%s: cdp %p (%s) not on active list", 168667864268SJason A. Harmening __func__, cdp, dev->si_name)); 168767864268SJason A. Harmening cdp->cdp_flags &= ~CDP_ON_ACTIVE_LIST; 1688828d6d12SKonstantin Belousov TAILQ_REMOVE(&cdevp_list, cdp, cdp_list); 1689828d6d12SKonstantin Belousov dev_unlock(); 1690828d6d12SKonstantin Belousov dev_rel(&cdp->cdp_c); 1691828d6d12SKonstantin Belousov } else 1692828d6d12SKonstantin Belousov dev_unlock(); 1693828d6d12SKonstantin Belousov 1694cb05b60aSAttilio Rao vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 16953f54a085SPoul-Henning Kamp return (0); 16963f54a085SPoul-Henning Kamp } 16973f54a085SPoul-Henning Kamp 16983f54a085SPoul-Henning Kamp static int 169921806f30SPoul-Henning Kamp devfs_rioctl(struct vop_ioctl_args *ap) 1700ff7c5a48SPoul-Henning Kamp { 1701c4df27d5SKonstantin Belousov struct vnode *vp; 1702ff7c5a48SPoul-Henning Kamp struct devfs_mount *dmp; 1703c4df27d5SKonstantin Belousov int error; 1704ff7c5a48SPoul-Henning Kamp 1705c4df27d5SKonstantin Belousov vp = ap->a_vp; 1706c4df27d5SKonstantin Belousov vn_lock(vp, LK_SHARED | LK_RETRY); 1707abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 1708b249ce48SMateusz Guzik VOP_UNLOCK(vp); 1709c4df27d5SKonstantin Belousov return (EBADF); 1710c4df27d5SKonstantin Belousov } 1711c4df27d5SKonstantin Belousov dmp = VFSTODEVFS(vp->v_mount); 1712e606a3c6SPoul-Henning Kamp sx_xlock(&dmp->dm_lock); 1713b249ce48SMateusz Guzik VOP_UNLOCK(vp); 1714828d6d12SKonstantin Belousov DEVFS_DMP_HOLD(dmp); 1715ff7c5a48SPoul-Henning Kamp devfs_populate(dmp); 1716828d6d12SKonstantin Belousov if (DEVFS_DMP_DROP(dmp)) { 1717828d6d12SKonstantin Belousov sx_xunlock(&dmp->dm_lock); 1718828d6d12SKonstantin Belousov devfs_unmount_final(dmp); 1719828d6d12SKonstantin Belousov return (ENOENT); 1720828d6d12SKonstantin Belousov } 1721214c8ff0SPoul-Henning Kamp error = devfs_rules_ioctl(dmp, ap->a_command, ap->a_data, ap->a_td); 1722e606a3c6SPoul-Henning Kamp sx_xunlock(&dmp->dm_lock); 1723ff7c5a48SPoul-Henning Kamp return (error); 1724ff7c5a48SPoul-Henning Kamp } 1725ff7c5a48SPoul-Henning Kamp 1726ff7c5a48SPoul-Henning Kamp static int 172721806f30SPoul-Henning Kamp devfs_rread(struct vop_read_args *ap) 1728ff7c5a48SPoul-Henning Kamp { 1729ff7c5a48SPoul-Henning Kamp 1730ff7c5a48SPoul-Henning Kamp if (ap->a_vp->v_type != VDIR) 1731ff7c5a48SPoul-Henning Kamp return (EINVAL); 1732ff7c5a48SPoul-Henning Kamp return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 1733ff7c5a48SPoul-Henning Kamp } 1734ff7c5a48SPoul-Henning Kamp 1735ff7c5a48SPoul-Henning Kamp static int 173621806f30SPoul-Henning Kamp devfs_setattr(struct vop_setattr_args *ap) 1737c32d0a1dSPoul-Henning Kamp { 1738c32d0a1dSPoul-Henning Kamp struct devfs_dirent *de; 1739c80d2913SPoul-Henning Kamp struct vattr *vap; 174096070273SPoul-Henning Kamp struct vnode *vp; 17410359a12eSAttilio Rao struct thread *td; 1742c80d2913SPoul-Henning Kamp int c, error; 1743c80d2913SPoul-Henning Kamp uid_t uid; 1744c80d2913SPoul-Henning Kamp gid_t gid; 1745c80d2913SPoul-Henning Kamp 1746c80d2913SPoul-Henning Kamp vap = ap->a_vap; 174796070273SPoul-Henning Kamp vp = ap->a_vp; 17480359a12eSAttilio Rao td = curthread; 1749c80d2913SPoul-Henning Kamp if ((vap->va_type != VNON) || 1750c80d2913SPoul-Henning Kamp (vap->va_nlink != VNOVAL) || 1751c80d2913SPoul-Henning Kamp (vap->va_fsid != VNOVAL) || 1752c80d2913SPoul-Henning Kamp (vap->va_fileid != VNOVAL) || 1753c80d2913SPoul-Henning Kamp (vap->va_blocksize != VNOVAL) || 1754eb7ba7f9SPoul-Henning Kamp (vap->va_flags != VNOVAL && vap->va_flags != 0) || 1755c80d2913SPoul-Henning Kamp (vap->va_rdev != VNOVAL) || 1756c80d2913SPoul-Henning Kamp ((int)vap->va_bytes != VNOVAL) || 1757c80d2913SPoul-Henning Kamp (vap->va_gen != VNOVAL)) { 1758c80d2913SPoul-Henning Kamp return (EINVAL); 1759c80d2913SPoul-Henning Kamp } 1760c32d0a1dSPoul-Henning Kamp 1761b63d070aSKonstantin Belousov error = devfs_populate_vp(vp); 1762b63d070aSKonstantin Belousov if (error != 0) 1763b63d070aSKonstantin Belousov return (error); 1764b63d070aSKonstantin Belousov 176596070273SPoul-Henning Kamp de = vp->v_data; 176696070273SPoul-Henning Kamp if (vp->v_type == VDIR) 1767c32d0a1dSPoul-Henning Kamp de = de->de_dir; 1768c32d0a1dSPoul-Henning Kamp 1769b63d070aSKonstantin Belousov c = 0; 1770c80d2913SPoul-Henning Kamp if (vap->va_uid == (uid_t)VNOVAL) 1771c80d2913SPoul-Henning Kamp uid = de->de_uid; 1772c80d2913SPoul-Henning Kamp else 1773c80d2913SPoul-Henning Kamp uid = vap->va_uid; 1774c80d2913SPoul-Henning Kamp if (vap->va_gid == (gid_t)VNOVAL) 1775c80d2913SPoul-Henning Kamp gid = de->de_gid; 1776c80d2913SPoul-Henning Kamp else 1777c80d2913SPoul-Henning Kamp gid = vap->va_gid; 1778c80d2913SPoul-Henning Kamp if (uid != de->de_uid || gid != de->de_gid) { 177916151645SEd Schouten if ((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 178016151645SEd Schouten (gid != de->de_gid && !groupmember(gid, ap->a_cred))) { 17810359a12eSAttilio Rao error = priv_check(td, PRIV_VFS_CHOWN); 1782b63d070aSKonstantin Belousov if (error != 0) 1783b63d070aSKonstantin Belousov goto ret; 1784acd3428bSRobert Watson } 1785c80d2913SPoul-Henning Kamp de->de_uid = uid; 1786c80d2913SPoul-Henning Kamp de->de_gid = gid; 1787c32d0a1dSPoul-Henning Kamp c = 1; 1788c32d0a1dSPoul-Henning Kamp } 178996070273SPoul-Henning Kamp 1790c80d2913SPoul-Henning Kamp if (vap->va_mode != (mode_t)VNOVAL) { 179116151645SEd Schouten if (ap->a_cred->cr_uid != de->de_uid) { 17920359a12eSAttilio Rao error = priv_check(td, PRIV_VFS_ADMIN); 1793b63d070aSKonstantin Belousov if (error != 0) 1794b63d070aSKonstantin Belousov goto ret; 1795acd3428bSRobert Watson } 1796c80d2913SPoul-Henning Kamp de->de_mode = vap->va_mode; 1797c32d0a1dSPoul-Henning Kamp c = 1; 1798c32d0a1dSPoul-Henning Kamp } 179911257f4dSBruce Evans 180011257f4dSBruce Evans if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 18017b81a399SKonstantin Belousov error = vn_utimes_perm(vp, vap, ap->a_cred, td); 18027b81a399SKonstantin Belousov if (error != 0) 1803b63d070aSKonstantin Belousov goto ret; 180411257f4dSBruce Evans if (vap->va_atime.tv_sec != VNOVAL) { 180511257f4dSBruce Evans if (vp->v_type == VCHR) 180611257f4dSBruce Evans vp->v_rdev->si_atime = vap->va_atime; 180711257f4dSBruce Evans else 1808c80d2913SPoul-Henning Kamp de->de_atime = vap->va_atime; 1809c32d0a1dSPoul-Henning Kamp } 1810c80d2913SPoul-Henning Kamp if (vap->va_mtime.tv_sec != VNOVAL) { 181111257f4dSBruce Evans if (vp->v_type == VCHR) 181211257f4dSBruce Evans vp->v_rdev->si_mtime = vap->va_mtime; 181311257f4dSBruce Evans else 1814c80d2913SPoul-Henning Kamp de->de_mtime = vap->va_mtime; 181511257f4dSBruce Evans } 1816c80d2913SPoul-Henning Kamp c = 1; 1817c80d2913SPoul-Henning Kamp } 1818c32d0a1dSPoul-Henning Kamp 181911257f4dSBruce Evans if (c) { 182011257f4dSBruce Evans if (vp->v_type == VCHR) 182111257f4dSBruce Evans vfs_timestamp(&vp->v_rdev->si_ctime); 182211257f4dSBruce Evans else 182311257f4dSBruce Evans vfs_timestamp(&de->de_mtime); 182411257f4dSBruce Evans } 1825b63d070aSKonstantin Belousov 1826b63d070aSKonstantin Belousov ret: 1827b63d070aSKonstantin Belousov sx_xunlock(&VFSTODEVFS(vp->v_mount)->dm_lock); 1828b63d070aSKonstantin Belousov return (error); 1829c32d0a1dSPoul-Henning Kamp } 1830c32d0a1dSPoul-Henning Kamp 18316742f328SRobert Watson #ifdef MAC 18326742f328SRobert Watson static int 183321806f30SPoul-Henning Kamp devfs_setlabel(struct vop_setlabel_args *ap) 18346742f328SRobert Watson { 18356742f328SRobert Watson struct vnode *vp; 18366742f328SRobert Watson struct devfs_dirent *de; 18376742f328SRobert Watson 18386742f328SRobert Watson vp = ap->a_vp; 18396742f328SRobert Watson de = vp->v_data; 18406742f328SRobert Watson 184130d239bcSRobert Watson mac_vnode_relabel(ap->a_cred, vp, ap->a_label); 184230d239bcSRobert Watson mac_devfs_update(vp->v_mount, de, vp); 18436742f328SRobert Watson 18446742f328SRobert Watson return (0); 18456742f328SRobert Watson } 18466742f328SRobert Watson #endif 18476742f328SRobert Watson 1848c32d0a1dSPoul-Henning Kamp static int 18492b68eb8eSMateusz Guzik devfs_stat_f(struct file *fp, struct stat *sb, struct ucred *cred) 185056dd3a61SPoul-Henning Kamp { 185156dd3a61SPoul-Henning Kamp 18522b68eb8eSMateusz Guzik return (vnops.fo_stat(fp, sb, cred)); 185356dd3a61SPoul-Henning Kamp } 185456dd3a61SPoul-Henning Kamp 185556dd3a61SPoul-Henning Kamp static int 185621806f30SPoul-Henning Kamp devfs_symlink(struct vop_symlink_args *ap) 18573f54a085SPoul-Henning Kamp { 1858ecde9a6dSPoul-Henning Kamp int i, error; 1859a481b90bSPoul-Henning Kamp struct devfs_dirent *dd; 186064040d39SJaakko Heinonen struct devfs_dirent *de, *de_covered, *de_dotdot; 1861a481b90bSPoul-Henning Kamp struct devfs_mount *dmp; 18623f54a085SPoul-Henning Kamp 1863dfd233edSAttilio Rao error = priv_check(curthread, PRIV_DEVFS_SYMLINK); 1864ecde9a6dSPoul-Henning Kamp if (error) 1865ecde9a6dSPoul-Henning Kamp return(error); 1866c32d0a1dSPoul-Henning Kamp dmp = VFSTODEVFS(ap->a_dvp->v_mount); 186789d10571SJaakko Heinonen if (devfs_populate_vp(ap->a_dvp) != 0) 186889d10571SJaakko Heinonen return (ENOENT); 186989d10571SJaakko Heinonen 18703f54a085SPoul-Henning Kamp dd = ap->a_dvp->v_data; 18713f54a085SPoul-Henning Kamp de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 1872d318c565SJaakko Heinonen de->de_flags = DE_USER; 18733f54a085SPoul-Henning Kamp de->de_uid = 0; 18743f54a085SPoul-Henning Kamp de->de_gid = 0; 1875ecde9a6dSPoul-Henning Kamp de->de_mode = 0755; 1876e606a3c6SPoul-Henning Kamp de->de_inode = alloc_unr(devfs_inos); 18774136388aSJaakko Heinonen de->de_dir = dd; 18783f54a085SPoul-Henning Kamp de->de_dirent->d_type = DT_LNK; 18793f54a085SPoul-Henning Kamp i = strlen(ap->a_target) + 1; 1880214c8ff0SPoul-Henning Kamp de->de_symlink = malloc(i, M_DEVFS, M_WAITOK); 18813f54a085SPoul-Henning Kamp bcopy(ap->a_target, de->de_symlink, i); 188274e62b1bSRobert Watson #ifdef MAC 188330d239bcSRobert Watson mac_devfs_create_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 188474e62b1bSRobert Watson #endif 188564040d39SJaakko Heinonen de_covered = devfs_find(dd, de->de_dirent->d_name, 188664040d39SJaakko Heinonen de->de_dirent->d_namlen, 0); 188764040d39SJaakko Heinonen if (de_covered != NULL) { 18882d843e7dSJaakko Heinonen if ((de_covered->de_flags & DE_USER) != 0) { 18892d843e7dSJaakko Heinonen devfs_delete(dmp, de, DEVFS_DEL_NORECURSE); 18902d843e7dSJaakko Heinonen sx_xunlock(&dmp->dm_lock); 18912d843e7dSJaakko Heinonen return (EEXIST); 18922d843e7dSJaakko Heinonen } 189364040d39SJaakko Heinonen KASSERT((de_covered->de_flags & DE_COVERED) == 0, 189464040d39SJaakko Heinonen ("devfs_symlink: entry %p already covered", de_covered)); 189564040d39SJaakko Heinonen de_covered->de_flags |= DE_COVERED; 189664040d39SJaakko Heinonen } 189764040d39SJaakko Heinonen 189864040d39SJaakko Heinonen de_dotdot = TAILQ_FIRST(&dd->de_dlist); /* "." */ 189964040d39SJaakko Heinonen de_dotdot = TAILQ_NEXT(de_dotdot, de_list); /* ".." */ 190064040d39SJaakko Heinonen TAILQ_INSERT_AFTER(&dd->de_dlist, de_dotdot, de, de_list); 1901d318c565SJaakko Heinonen devfs_dir_ref_de(dmp, dd); 1902ef456eecSJaakko Heinonen devfs_rules_apply(dmp, de); 190364040d39SJaakko Heinonen 19049968a426SKonstantin Belousov return (devfs_allocv(de, ap->a_dvp->v_mount, LK_EXCLUSIVE, ap->a_vpp)); 19053f54a085SPoul-Henning Kamp } 19063f54a085SPoul-Henning Kamp 1907e4650294SJohn Baldwin static int 1908e4650294SJohn Baldwin devfs_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td) 1909e4650294SJohn Baldwin { 1910e4650294SJohn Baldwin 1911e4650294SJohn Baldwin return (vnops.fo_truncate(fp, length, cred, td)); 1912e4650294SJohn Baldwin } 1913e4650294SJohn Baldwin 1914ff7c5a48SPoul-Henning Kamp static int 191564548150SKonstantin Belousov devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, 191664548150SKonstantin Belousov int flags, struct thread *td) 191756dd3a61SPoul-Henning Kamp { 191856dd3a61SPoul-Henning Kamp struct cdev *dev; 1919526d0bd5SKonstantin Belousov int error, ioflag, ref; 1920526d0bd5SKonstantin Belousov ssize_t resid; 192156dd3a61SPoul-Henning Kamp struct cdevsw *dsw; 19227818e0a5SKonstantin Belousov struct file *fpop; 192356dd3a61SPoul-Henning Kamp 1924bf3e483bSKonstantin Belousov if (uio->uio_resid > DEVFS_IOSIZE_MAX) 1925bf3e483bSKonstantin Belousov return (EINVAL); 19267818e0a5SKonstantin Belousov fpop = td->td_fpop; 19273979450bSKonstantin Belousov error = devfs_fp_check(fp, &dev, &dsw, &ref); 1928f12aa60cSKonstantin Belousov if (error != 0) { 1929f12aa60cSKonstantin Belousov error = vnops.fo_write(fp, uio, cred, flags, td); 1930aac5167cSPoul-Henning Kamp return (error); 1931f12aa60cSKonstantin Belousov } 193256dd3a61SPoul-Henning Kamp KASSERT(uio->uio_td == td, ("uio_td %p is not td %p", uio->uio_td, td)); 193350a36c11SPoul-Henning Kamp ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT | O_FSYNC); 193450a36c11SPoul-Henning Kamp if (ioflag & O_DIRECT) 193556dd3a61SPoul-Henning Kamp ioflag |= IO_DIRECT; 1936c5c1199cSKonstantin Belousov foffset_lock_uio(fp, uio, flags | FOF_NOLOCK); 193756dd3a61SPoul-Henning Kamp 193856dd3a61SPoul-Henning Kamp resid = uio->uio_resid; 193956dd3a61SPoul-Henning Kamp 194056dd3a61SPoul-Henning Kamp error = dsw->d_write(dev, uio, ioflag); 1941bda2eb9aSKonstantin Belousov if (uio->uio_resid != resid || (error == 0 && resid != 0)) { 1942bda2eb9aSKonstantin Belousov devfs_timestamp(&dev->si_ctime); 194356dd3a61SPoul-Henning Kamp dev->si_mtime = dev->si_ctime; 194456dd3a61SPoul-Henning Kamp } 19457818e0a5SKonstantin Belousov td->td_fpop = fpop; 19463979450bSKonstantin Belousov dev_relthread(dev, ref); 194756dd3a61SPoul-Henning Kamp 1948f2706588SThomas Munro foffset_unlock_uio(fp, uio, flags | FOF_NOLOCK | FOF_NEXTOFF_W); 194956dd3a61SPoul-Henning Kamp return (error); 195056dd3a61SPoul-Henning Kamp } 1951ff7c5a48SPoul-Henning Kamp 19527077c426SJohn Baldwin static int 19537077c426SJohn Baldwin devfs_mmap_f(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t size, 19547077c426SJohn Baldwin vm_prot_t prot, vm_prot_t cap_maxprot, int flags, vm_ooffset_t foff, 19557077c426SJohn Baldwin struct thread *td) 19567077c426SJohn Baldwin { 19577077c426SJohn Baldwin struct cdev *dev; 19587077c426SJohn Baldwin struct cdevsw *dsw; 19597077c426SJohn Baldwin struct mount *mp; 19607077c426SJohn Baldwin struct vnode *vp; 19617077c426SJohn Baldwin struct file *fpop; 19627077c426SJohn Baldwin vm_object_t object; 19637077c426SJohn Baldwin vm_prot_t maxprot; 19647077c426SJohn Baldwin int error, ref; 19657077c426SJohn Baldwin 19667077c426SJohn Baldwin vp = fp->f_vnode; 19677077c426SJohn Baldwin 19687077c426SJohn Baldwin /* 19697077c426SJohn Baldwin * Ensure that file and memory protections are 19707077c426SJohn Baldwin * compatible. 19717077c426SJohn Baldwin */ 19727077c426SJohn Baldwin mp = vp->v_mount; 1973ecc6c515SKonstantin Belousov if (mp != NULL && (mp->mnt_flag & MNT_NOEXEC) != 0) { 19747077c426SJohn Baldwin maxprot = VM_PROT_NONE; 1975ecc6c515SKonstantin Belousov if ((prot & VM_PROT_EXECUTE) != 0) 1976ecc6c515SKonstantin Belousov return (EACCES); 1977ecc6c515SKonstantin Belousov } else 19787077c426SJohn Baldwin maxprot = VM_PROT_EXECUTE; 19797077c426SJohn Baldwin if ((fp->f_flag & FREAD) != 0) 19807077c426SJohn Baldwin maxprot |= VM_PROT_READ; 19817077c426SJohn Baldwin else if ((prot & VM_PROT_READ) != 0) 19827077c426SJohn Baldwin return (EACCES); 19837077c426SJohn Baldwin 19847077c426SJohn Baldwin /* 1985fada4adfSJohn Baldwin * If we are sharing potential changes via MAP_SHARED and we 1986fada4adfSJohn Baldwin * are trying to get write permission although we opened it 1987fada4adfSJohn Baldwin * without asking for it, bail out. 1988fada4adfSJohn Baldwin * 1989fada4adfSJohn Baldwin * Note that most character devices always share mappings. 1990fada4adfSJohn Baldwin * The one exception is that D_MMAP_ANON devices 1991fada4adfSJohn Baldwin * (i.e. /dev/zero) permit private writable mappings. 1992fada4adfSJohn Baldwin * 1993fada4adfSJohn Baldwin * Rely on vm_mmap_cdev() to fail invalid MAP_PRIVATE requests 1994fada4adfSJohn Baldwin * as well as updating maxprot to permit writing for 1995fada4adfSJohn Baldwin * D_MMAP_ANON devices rather than doing that here. 19967077c426SJohn Baldwin */ 1997fada4adfSJohn Baldwin if ((flags & MAP_SHARED) != 0) { 19987077c426SJohn Baldwin if ((fp->f_flag & FWRITE) != 0) 19997077c426SJohn Baldwin maxprot |= VM_PROT_WRITE; 20007077c426SJohn Baldwin else if ((prot & VM_PROT_WRITE) != 0) 20017077c426SJohn Baldwin return (EACCES); 2002fada4adfSJohn Baldwin } 20037077c426SJohn Baldwin maxprot &= cap_maxprot; 20047077c426SJohn Baldwin 20057077c426SJohn Baldwin fpop = td->td_fpop; 20067077c426SJohn Baldwin error = devfs_fp_check(fp, &dev, &dsw, &ref); 20077077c426SJohn Baldwin if (error != 0) 20087077c426SJohn Baldwin return (error); 20097077c426SJohn Baldwin 20107077c426SJohn Baldwin error = vm_mmap_cdev(td, size, prot, &maxprot, &flags, dev, dsw, &foff, 20117077c426SJohn Baldwin &object); 20127077c426SJohn Baldwin td->td_fpop = fpop; 20137077c426SJohn Baldwin dev_relthread(dev, ref); 20147077c426SJohn Baldwin if (error != 0) 20157077c426SJohn Baldwin return (error); 20167077c426SJohn Baldwin 20177077c426SJohn Baldwin error = vm_mmap_object(map, addr, size, prot, maxprot, flags, object, 20187077c426SJohn Baldwin foff, FALSE, td); 20197077c426SJohn Baldwin if (error != 0) 20207077c426SJohn Baldwin vm_object_deallocate(object); 20217077c426SJohn Baldwin return (error); 20227077c426SJohn Baldwin } 20237077c426SJohn Baldwin 2024b43ab0e3SPoul-Henning Kamp dev_t 2025b43ab0e3SPoul-Henning Kamp dev2udev(struct cdev *x) 2026b43ab0e3SPoul-Henning Kamp { 2027b43ab0e3SPoul-Henning Kamp if (x == NULL) 2028b43ab0e3SPoul-Henning Kamp return (NODEV); 202905427aafSKonstantin Belousov return (cdev2priv(x)->cdp_inode); 2030b43ab0e3SPoul-Henning Kamp } 2031b43ab0e3SPoul-Henning Kamp 20325c41d888SKonstantin Belousov static int 20335c41d888SKonstantin Belousov devfs_cmp_f(struct file *fp1, struct file *fp2, struct thread *td) 20345c41d888SKonstantin Belousov { 20355c41d888SKonstantin Belousov if (fp2->f_type != DTYPE_VNODE || fp2->f_ops != &devfs_ops_f) 20365c41d888SKonstantin Belousov return (3); 20375c41d888SKonstantin Belousov return (kcmp_cmp((uintptr_t)fp1->f_data, (uintptr_t)fp2->f_data)); 20385c41d888SKonstantin Belousov } 20395c41d888SKonstantin Belousov 2040*ef9ffb85SMark Johnston static const struct fileops devfs_ops_f = { 204121806f30SPoul-Henning Kamp .fo_read = devfs_read_f, 204221806f30SPoul-Henning Kamp .fo_write = devfs_write_f, 2043e4650294SJohn Baldwin .fo_truncate = devfs_truncate_f, 204421806f30SPoul-Henning Kamp .fo_ioctl = devfs_ioctl_f, 204521806f30SPoul-Henning Kamp .fo_poll = devfs_poll_f, 204621806f30SPoul-Henning Kamp .fo_kqfilter = devfs_kqfilter_f, 204721806f30SPoul-Henning Kamp .fo_stat = devfs_stat_f, 204821806f30SPoul-Henning Kamp .fo_close = devfs_close_f, 20499c00bb91SKonstantin Belousov .fo_chmod = vn_chmod, 20509c00bb91SKonstantin Belousov .fo_chown = vn_chown, 2051b1dd38f4SKonstantin Belousov .fo_sendfile = vn_sendfile, 2052c0a46535SKonstantin Belousov .fo_seek = vn_seek, 20539696feebSJohn Baldwin .fo_fill_kinfo = vn_fill_kinfo, 20547077c426SJohn Baldwin .fo_mmap = devfs_mmap_f, 20555c41d888SKonstantin Belousov .fo_cmp = devfs_cmp_f, 205621806f30SPoul-Henning Kamp .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE 205721806f30SPoul-Henning Kamp }; 205821806f30SPoul-Henning Kamp 2059af326aceSConrad Meyer /* Vops for non-CHR vnodes in /dev. */ 206021806f30SPoul-Henning Kamp static struct vop_vector devfs_vnodeops = { 206121806f30SPoul-Henning Kamp .vop_default = &default_vnodeops, 206221806f30SPoul-Henning Kamp 206321806f30SPoul-Henning Kamp .vop_access = devfs_access, 206421806f30SPoul-Henning Kamp .vop_getattr = devfs_getattr, 206521806f30SPoul-Henning Kamp .vop_ioctl = devfs_rioctl, 206621806f30SPoul-Henning Kamp .vop_lookup = devfs_lookup, 206721806f30SPoul-Henning Kamp .vop_mknod = devfs_mknod, 206821806f30SPoul-Henning Kamp .vop_pathconf = devfs_pathconf, 206921806f30SPoul-Henning Kamp .vop_read = devfs_rread, 207021806f30SPoul-Henning Kamp .vop_readdir = devfs_readdir, 207121806f30SPoul-Henning Kamp .vop_readlink = devfs_readlink, 207221806f30SPoul-Henning Kamp .vop_reclaim = devfs_reclaim, 207321806f30SPoul-Henning Kamp .vop_remove = devfs_remove, 207421806f30SPoul-Henning Kamp .vop_revoke = devfs_revoke, 207521806f30SPoul-Henning Kamp .vop_setattr = devfs_setattr, 207621806f30SPoul-Henning Kamp #ifdef MAC 207721806f30SPoul-Henning Kamp .vop_setlabel = devfs_setlabel, 207821806f30SPoul-Henning Kamp #endif 207921806f30SPoul-Henning Kamp .vop_symlink = devfs_symlink, 20804c44fd37SJoe Marcus Clarke .vop_vptocnp = devfs_vptocnp, 2081f8935a96SMateusz Guzik .vop_lock1 = vop_lock, 2082f8935a96SMateusz Guzik .vop_unlock = vop_unlock, 2083f8935a96SMateusz Guzik .vop_islocked = vop_islocked, 20843ffcfa59SMateusz Guzik .vop_add_writecount = vop_stdadd_writecount_nomsync, 208521806f30SPoul-Henning Kamp }; 20866fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(devfs_vnodeops); 208721806f30SPoul-Henning Kamp 2088af326aceSConrad Meyer /* Vops for VCHR vnodes in /dev. */ 20896e572e08SEdward Tomasz Napierala static struct vop_vector devfs_specops = { 209021806f30SPoul-Henning Kamp .vop_default = &default_vnodeops, 209121806f30SPoul-Henning Kamp 209221806f30SPoul-Henning Kamp .vop_access = devfs_access, 209321806f30SPoul-Henning Kamp .vop_bmap = VOP_PANIC, 209421806f30SPoul-Henning Kamp .vop_close = devfs_close, 209521806f30SPoul-Henning Kamp .vop_create = VOP_PANIC, 20961a2dbd1aSEdward Tomasz Napierala .vop_fsync = vop_stdfsync, 209721806f30SPoul-Henning Kamp .vop_getattr = devfs_getattr, 2098af326aceSConrad Meyer .vop_ioctl = devfs_ioctl, 209921806f30SPoul-Henning Kamp .vop_link = VOP_PANIC, 210021806f30SPoul-Henning Kamp .vop_mkdir = VOP_PANIC, 210121806f30SPoul-Henning Kamp .vop_mknod = VOP_PANIC, 210221806f30SPoul-Henning Kamp .vop_open = devfs_open, 210321806f30SPoul-Henning Kamp .vop_pathconf = devfs_pathconf, 2104f12aa60cSKonstantin Belousov .vop_poll = dead_poll, 210521806f30SPoul-Henning Kamp .vop_print = devfs_print, 2106f12aa60cSKonstantin Belousov .vop_read = dead_read, 210721806f30SPoul-Henning Kamp .vop_readdir = VOP_PANIC, 210821806f30SPoul-Henning Kamp .vop_readlink = VOP_PANIC, 210921806f30SPoul-Henning Kamp .vop_reallocblks = VOP_PANIC, 21102d5bba3aSKonstantin Belousov .vop_reclaim = devfs_reclaim_vchr, 211121806f30SPoul-Henning Kamp .vop_remove = devfs_remove, 211221806f30SPoul-Henning Kamp .vop_rename = VOP_PANIC, 211321806f30SPoul-Henning Kamp .vop_revoke = devfs_revoke, 211421806f30SPoul-Henning Kamp .vop_rmdir = VOP_PANIC, 211521806f30SPoul-Henning Kamp .vop_setattr = devfs_setattr, 211621806f30SPoul-Henning Kamp #ifdef MAC 211721806f30SPoul-Henning Kamp .vop_setlabel = devfs_setlabel, 211821806f30SPoul-Henning Kamp #endif 211921806f30SPoul-Henning Kamp .vop_strategy = VOP_PANIC, 212021806f30SPoul-Henning Kamp .vop_symlink = VOP_PANIC, 21214c44fd37SJoe Marcus Clarke .vop_vptocnp = devfs_vptocnp, 2122f12aa60cSKonstantin Belousov .vop_write = dead_write, 2123f8935a96SMateusz Guzik .vop_lock1 = vop_lock, 2124f8935a96SMateusz Guzik .vop_unlock = vop_unlock, 2125f8935a96SMateusz Guzik .vop_islocked = vop_islocked, 21263ffcfa59SMateusz Guzik .vop_add_writecount = vop_stdadd_writecount_nomsync, 212721806f30SPoul-Henning Kamp }; 21286fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(devfs_specops); 212921806f30SPoul-Henning Kamp 213010eee285SPoul-Henning Kamp /* 213110eee285SPoul-Henning Kamp * Our calling convention to the device drivers used to be that we passed 213210eee285SPoul-Henning Kamp * vnode.h IO_* flags to read()/write(), but we're moving to fcntl.h O_ 213310eee285SPoul-Henning Kamp * flags instead since that's what open(), close() and ioctl() takes and 213410eee285SPoul-Henning Kamp * we don't really want vnode.h in device drivers. 213510eee285SPoul-Henning Kamp * We solved the source compatibility by redefining some vnode flags to 213610eee285SPoul-Henning Kamp * be the same as the fcntl ones and by sending down the bitwise OR of 213710eee285SPoul-Henning Kamp * the respective fcntl/vnode flags. These CTASSERTS make sure nobody 213810eee285SPoul-Henning Kamp * pulls the rug out under this. 213910eee285SPoul-Henning Kamp */ 214010eee285SPoul-Henning Kamp CTASSERT(O_NONBLOCK == IO_NDELAY); 214110eee285SPoul-Henning Kamp CTASSERT(O_FSYNC == IO_SYNC); 2142