#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 <fs/fdescfs/fdesc.h>
static MALLOC_DEFINE(M_FDESCMNT, "fdesc_mount", "FDESC mount structure");
static vfs_cmount_t fdesc_cmount;
static vfs_mount_t fdesc_mount;
static vfs_unmount_t fdesc_unmount;
static vfs_statfs_t fdesc_statfs;
static vfs_root_t fdesc_root;
int
fdesc_cmount(struct mntarg *ma, void *data, uint64_t flags)
{
return kernel_mount(ma, flags);
}
static int
fdesc_mount(struct mount *mp)
{
struct fdescmount *fmp;
struct vnode *rvp;
int error;
if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS))
return (EOPNOTSUPP);
fmp = malloc(sizeof(struct fdescmount), M_FDESCMNT, M_WAITOK);
mp->mnt_data = fmp;
fmp->flags = 0;
if (vfs_getopt(mp->mnt_optnew, "linrdlnk", NULL, NULL) == 0)
fmp->flags |= FMNT_LINRDLNKF;
if (vfs_getopt(mp->mnt_optnew, "rdlnk", NULL, NULL) == 0)
fmp->flags |= FMNT_RDLNKF;
if (vfs_getopt(mp->mnt_optnew, "nodup", NULL, NULL) == 0)
fmp->flags |= FMNT_NODUP;
error = fdesc_allocvp(Froot, -1, FD_ROOT, mp, &rvp);
if (error) {
free(fmp, M_FDESCMNT);
mp->mnt_data = NULL;
return (error);
}
VN_LOCK_ASHARE(rvp);
rvp->v_type = VDIR;
rvp->v_vflag |= VV_ROOT;
fmp->f_root = rvp;
VOP_UNLOCK(rvp);
MNT_ILOCK(mp);
mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
MNT_IUNLOCK(mp);
vfs_getnewfsid(mp);
vfs_mountedfrom(mp, "fdescfs");
return (0);
}
static int
fdesc_unmount(struct mount *mp, int mntflags)
{
struct fdescmount *fmp;
int error, flags;
flags = 0;
fmp = mp->mnt_data;
if (mntflags & MNT_FORCE) {
mtx_lock(&fdesc_hashmtx);
fmp->flags |= FMNT_UNMOUNTF;
mtx_unlock(&fdesc_hashmtx);
flags |= FORCECLOSE;
}
if ((error = vflush(mp, 1, flags, curthread)) != 0)
return (error);
mp->mnt_data = NULL;
free(fmp, M_FDESCMNT);
return (0);
}
static int
fdesc_root(struct mount *mp, int flags, struct vnode **vpp)
{
struct vnode *vp;
vp = VFSTOFDESC(mp)->f_root;
vget(vp, flags | LK_RETRY);
*vpp = vp;
return (0);
}
static int
fdesc_statfs(struct mount *mp, struct statfs *sbp)
{
struct thread *td;
struct filedesc *fdp;
int lim;
int i;
int last;
int freefd;
uint64_t limit;
td = curthread;
lim = lim_cur(td, RLIMIT_NOFILE);
fdp = td->td_proc->p_fd;
FILEDESC_SLOCK(fdp);
limit = racct_get_limit(td->td_proc, RACCT_NOFILE);
if (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++;
if (fdp->fd_nfiles < lim)
freefd += (lim - fdp->fd_nfiles);
FILEDESC_SUNLOCK(fdp);
sbp->f_flags = mp->mnt_flag & MNT_IGNORE;
sbp->f_bsize = DEV_BSIZE;
sbp->f_iosize = DEV_BSIZE;
sbp->f_blocks = 2;
sbp->f_bfree = 2;
sbp->f_bavail = 2;
sbp->f_files = lim + 1;
sbp->f_ffree = freefd;
return (0);
}
static struct vfsops fdesc_vfsops = {
.vfs_cmount = fdesc_cmount,
.vfs_init = fdesc_init,
.vfs_mount = fdesc_mount,
.vfs_root = fdesc_root,
.vfs_statfs = fdesc_statfs,
.vfs_uninit = fdesc_uninit,
.vfs_unmount = fdesc_unmount,
};
VFS_SET(fdesc_vfsops, fdescfs, VFCF_SYNTHETIC | VFCF_JAIL);