| /*- |
| * Copyright (c) 1992, 1993, 1995 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * This code is derived from software donated to Berkeley by |
| * Jan-Simon Pendry. |
| * |
| * Copyright 2020-2026 Rivoreo |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the University nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #include <sys/param.h> |
| #include <sys/systm.h> |
| #include <sys/filedesc.h> |
| #include <sys/kernel.h> |
| #include <sys/jail.h> |
| #include <sys/lock.h> |
| #include <sys/mutex.h> |
| #include <sys/malloc.h> |
| #include <sys/mount.h> |
| #include <sys/proc.h> |
| #include <sys/racct.h> |
| #include <sys/resourcevar.h> |
| #include <sys/vnode.h> |
| #include "fdfs.h" |
| |
| static MALLOC_DEFINE(M_FDFSMNT, "fdfs_mount", "FDFS mount structure"); |
| |
| static vfs_mount_t fdfs_mount; |
| static vfs_unmount_t fdfs_unmount; |
| static vfs_statfs_t fdfs_statfs; |
| static vfs_root_t fdfs_root; |
| |
| static int |
| fdfs_mount(struct mount *mp) |
| { |
| struct fdfsmount *fmp; |
| struct thread *td = curthread; |
| struct vnode *rvp; |
| |
| if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_FDESCFS)) { |
| return (EPERM); |
| } |
| |
| /* |
| * Update is a no-op |
| */ |
| if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) { |
| return (EOPNOTSUPP); |
| } |
| |
| fmp = malloc(sizeof(struct fdfsmount), M_FDFSMNT, M_WAITOK); |
| |
| /* |
| * We need to initialize a few bits of our local mount point struct to |
| * avoid confusion in allocvp. |
| */ |
| mp->mnt_data = (qaddr_t) fmp; |
| fmp->flags = 0; |
| |
| int error = fdfs_allocvp(Froot, -1, FD_ROOT, mp, &rvp); |
| if (error) { |
| free(fmp, M_FDFSMNT); |
| mp->mnt_data = NULL; |
| return (error); |
| } |
| rvp->v_type = VDIR; |
| rvp->v_vflag |= VV_ROOT; |
| fmp->f_root = rvp; |
| VOP_UNLOCK(rvp, 0); |
| /* XXX -- don't mark as local to work around fts() problems */ |
| /*mp->mnt_flag |= MNT_LOCAL;*/ |
| vfs_getnewfsid(mp); |
| vfs_mountedfrom(mp, "fdfs"); |
| return (0); |
| } |
| |
| static int |
| fdfs_unmount(struct mount *mp, int mntflags) |
| { |
| struct fdfsmount *fmp = (struct fdfsmount *)mp->mnt_data; |
| int vflush_flags = 0; |
| if (mntflags & MNT_FORCE) { |
| /* The hash mutex protects the private mount flags. */ |
| mtx_lock(&fdfs_hashmtx); |
| fmp->flags |= FMNT_UNMOUNTF; |
| mtx_unlock(&fdfs_hashmtx); |
| vflush_flags |= FORCECLOSE; |
| } |
| |
| /* |
| * Clear out buffer cache. I don't think we |
| * ever get anything cached at this level at the |
| * moment, but who knows... |
| * |
| * There is 1 extra root vnode reference corresponding |
| * to f_root. |
| */ |
| int e = vflush(mp, 1, vflush_flags, curthread); |
| if(e) return e; |
| |
| /* |
| * Finally, throw away the fdescmount structure. Hold the hashmtx to |
| * protect the fdescmount structure. |
| */ |
| mtx_lock(&fdfs_hashmtx); |
| caddr_t data = mp->mnt_data; |
| mp->mnt_data = NULL; |
| mtx_unlock(&fdfs_hashmtx); |
| free(data, M_FDFSMNT); /* XXX */ |
| |
| return 0; |
| } |
| |
| static int |
| fdfs_root(struct mount *mp, int flags, struct vnode **vpp) |
| { |
| /* |
| * Return locked reference to root. |
| */ |
| struct vnode *vp = VFSTOFDFS(mp)->f_root; |
| vget(vp, LK_EXCLUSIVE | LK_RETRY, curthread); |
| *vpp = vp; |
| return (0); |
| } |
| |
| static int |
| fdfs_statfs(struct mount *mp, struct statfs *sbp) |
| { |
| struct thread *td = curthread; |
| struct filedesc *fdp = td->td_proc->p_fd; |
| int lim; |
| int i; |
| int last; |
| int freefd; |
| uint64_t limit; |
| |
| /* |
| * Compute number of free file descriptors. |
| * [ Strange results will ensue if the open file |
| * limit is ever reduced below the current number |
| * of open files... ] |
| */ |
| lim = lim_cur(td, RLIMIT_NOFILE); |
| FILEDESC_SLOCK(fdp); |
| limit = racct_get_limit(td->td_proc, RACCT_NOFILE); |
| if((uint64_t)lim > limit) lim = limit; |
| last = min(fdp->fd_nfiles, lim); |
| freefd = 0; |
| for (i = fdp->fd_freefile; i < last; i++) { |
| if(fdp->fd_ofiles[i].fde_file == NULL) freefd++; |
| } |
| |
| /* |
| * Adjust for the fact that the fdesc array may not |
| * have been fully allocated yet. |
| */ |
| if (fdp->fd_nfiles < lim) { |
| freefd += (lim - fdp->fd_nfiles); |
| } |
| FILEDESC_SUNLOCK(fdp); |
| |
| sbp->f_flags = 0; |
| sbp->f_bsize = DEV_BSIZE; |
| sbp->f_iosize = DEV_BSIZE; |
| sbp->f_blocks = 0; |
| sbp->f_bfree = 0; |
| sbp->f_bavail = 0; |
| sbp->f_files = lim + 1; /* Allow for "." */ |
| sbp->f_ffree = freefd; /* See comments above */ |
| return (0); |
| } |
| |
| static struct vfsops fdfs_vfsops = { |
| .vfs_init = fdfs_init, |
| .vfs_mount = fdfs_mount, |
| .vfs_root = fdfs_root, |
| .vfs_statfs = fdfs_statfs, |
| .vfs_uninit = fdfs_uninit, |
| .vfs_unmount = fdfs_unmount, |
| }; |
| |
| VFS_SET(fdfs_vfsops, fdfs, VFCF_SYNTHETIC | VFCF_JAIL); |