/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1992, 1993, 19954* The Regents of the University of California. All rights reserved.5*6* This code is derived from software donated to Berkeley by7* Jan-Simon Pendry.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its contributors18* may be used to endorse or promote products derived from this software19* without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/3334/*35* /dev/fd Filesystem36*/3738#include <sys/param.h>39#include <sys/systm.h>40#include <sys/filedesc.h>41#include <sys/kernel.h>42#include <sys/jail.h>43#include <sys/lock.h>44#include <sys/mutex.h>45#include <sys/malloc.h>46#include <sys/mount.h>47#include <sys/proc.h>48#include <sys/racct.h>49#include <sys/resourcevar.h>50#include <sys/vnode.h>5152#include <fs/fdescfs/fdesc.h>5354static MALLOC_DEFINE(M_FDESCMNT, "fdesc_mount", "FDESC mount structure");5556static vfs_cmount_t fdesc_cmount;57static vfs_mount_t fdesc_mount;58static vfs_unmount_t fdesc_unmount;59static vfs_statfs_t fdesc_statfs;60static vfs_root_t fdesc_root;6162/*63* Compatibility shim for old mount(2) system call.64*/65int66fdesc_cmount(struct mntarg *ma, void *data, uint64_t flags)67{6869return kernel_mount(ma, flags);70}7172/*73* Mount the per-process file descriptors (/dev/fd)74*/75static int76fdesc_mount(struct mount *mp)77{78struct fdescmount *fmp;79struct vnode *rvp;80int error;8182/*83* Update is a no-op84*/85if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS))86return (EOPNOTSUPP);8788fmp = malloc(sizeof(struct fdescmount), M_FDESCMNT, M_WAITOK);8990/*91* We need to initialize a few bits of our local mount point struct to92* avoid confusion in allocvp.93*/94mp->mnt_data = fmp;95fmp->flags = 0;96if (vfs_getopt(mp->mnt_optnew, "linrdlnk", NULL, NULL) == 0)97fmp->flags |= FMNT_LINRDLNKF;98if (vfs_getopt(mp->mnt_optnew, "rdlnk", NULL, NULL) == 0)99fmp->flags |= FMNT_RDLNKF;100if (vfs_getopt(mp->mnt_optnew, "nodup", NULL, NULL) == 0)101fmp->flags |= FMNT_NODUP;102error = fdesc_allocvp(Froot, -1, FD_ROOT, mp, &rvp);103if (error) {104free(fmp, M_FDESCMNT);105mp->mnt_data = NULL;106return (error);107}108VN_LOCK_ASHARE(rvp);109rvp->v_type = VDIR;110rvp->v_vflag |= VV_ROOT;111fmp->f_root = rvp;112VOP_UNLOCK(rvp);113114MNT_ILOCK(mp);115/* XXX -- don't mark as local to work around fts() problems */116/*mp->mnt_flag |= MNT_LOCAL;*/117/*118* Enable shared locking so that there is no contention on the root119* vnode. Note only root vnode enables shared locking for itself,120* so this end up being a nop for the rest.121*/122mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;123MNT_IUNLOCK(mp);124125vfs_getnewfsid(mp);126127vfs_mountedfrom(mp, "fdescfs");128return (0);129}130131static int132fdesc_unmount(struct mount *mp, int mntflags)133{134struct fdescmount *fmp;135int error, flags;136137flags = 0;138fmp = mp->mnt_data;139if (mntflags & MNT_FORCE) {140/* The hash mutex protects the private mount flags. */141mtx_lock(&fdesc_hashmtx);142fmp->flags |= FMNT_UNMOUNTF;143mtx_unlock(&fdesc_hashmtx);144flags |= FORCECLOSE;145}146147/*148* Clear out buffer cache. I don't think we149* ever get anything cached at this level at the150* moment, but who knows...151*152* There is 1 extra root vnode reference corresponding153* to f_root.154*/155if ((error = vflush(mp, 1, flags, curthread)) != 0)156return (error);157158/*159* Finally, throw away the fdescmount structure.160*/161mp->mnt_data = NULL;162free(fmp, M_FDESCMNT);163return (0);164}165166static int167fdesc_root(struct mount *mp, int flags, struct vnode **vpp)168{169struct vnode *vp;170171/*172* Return locked reference to root.173*/174vp = VFSTOFDESC(mp)->f_root;175vget(vp, flags | LK_RETRY);176*vpp = vp;177return (0);178}179180static int181fdesc_statfs(struct mount *mp, struct statfs *sbp)182{183struct thread *td;184struct filedesc *fdp;185int lim;186int i;187int last;188int freefd;189uint64_t limit;190191td = curthread;192193/*194* Compute number of free file descriptors.195* [ Strange results will ensue if the open file196* limit is ever reduced below the current number197* of open files... ]198*/199lim = lim_cur(td, RLIMIT_NOFILE);200fdp = td->td_proc->p_fd;201FILEDESC_SLOCK(fdp);202limit = racct_get_limit(td->td_proc, RACCT_NOFILE);203if (lim > limit)204lim = limit;205last = min(fdp->fd_nfiles, lim);206freefd = 0;207for (i = fdp->fd_freefile; i < last; i++)208if (fdp->fd_ofiles[i].fde_file == NULL)209freefd++;210211/*212* Adjust for the fact that the fdesc array may not213* have been fully allocated yet.214*/215if (fdp->fd_nfiles < lim)216freefd += (lim - fdp->fd_nfiles);217FILEDESC_SUNLOCK(fdp);218219sbp->f_flags = mp->mnt_flag & MNT_IGNORE;220sbp->f_bsize = DEV_BSIZE;221sbp->f_iosize = DEV_BSIZE;222sbp->f_blocks = 2; /* 1K to keep df happy */223sbp->f_bfree = 2;224sbp->f_bavail = 2;225sbp->f_files = lim + 1; /* Allow for "." */226sbp->f_ffree = freefd; /* See comments above */227return (0);228}229230static struct vfsops fdesc_vfsops = {231.vfs_cmount = fdesc_cmount,232.vfs_init = fdesc_init,233.vfs_mount = fdesc_mount,234.vfs_root = fdesc_root,235.vfs_statfs = fdesc_statfs,236.vfs_uninit = fdesc_uninit,237.vfs_unmount = fdesc_unmount,238};239240VFS_SET(fdesc_vfsops, fdescfs, VFCF_SYNTHETIC | VFCF_JAIL);241242243