#include <sys/atomic.h>
#include <sys/cmn_err.h>
#include <sys/errno.h>
#include <sys/mount.h>
#include <sys/objfs.h>
#include <sys/objfs_impl.h>
#include <sys/vfs_opreg.h>
#include <sys/policy.h>
#include <sys/sunddi.h>
#include <sys/sysmacros.h>
#include <sys/systm.h>
vnodeops_t *objfs_ops_root;
vnodeops_t *objfs_ops_odir;
vnodeops_t *objfs_ops_data;
static const fs_operation_def_t objfs_vfstops[];
static gfs_opsvec_t objfs_opsvec[];
static int objfs_init(int, char *);
static mntopts_t objfs_mntopts = {
0,
NULL
};
static vfsdef_t vfw = {
VFSDEF_VERSION,
"objfs",
objfs_init,
VSW_HASPROTO | VSW_ZMOUNT,
&objfs_mntopts,
};
extern struct mod_ops mod_fsops;
static struct modlfs modlfs = {
&mod_fsops, "kernel object filesystem", &vfw
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlfs, NULL
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
int
_fini(void)
{
return (EBUSY);
}
static int objfs_fstype;
static major_t objfs_major;
static minor_t objfs_minor;
static gfs_opsvec_t objfs_opsvec[] = {
{ "objfs root directory", objfs_tops_root, &objfs_ops_root },
{ "objfs object directory", objfs_tops_odir, &objfs_ops_odir },
{ "objfs data file", objfs_tops_data, &objfs_ops_data },
{ NULL }
};
static int
objfs_init(int fstype, char *name)
{
vfsops_t *vfsops;
int error;
objfs_fstype = fstype;
if (error = vfs_setfsops(fstype, objfs_vfstops, &vfsops)) {
cmn_err(CE_WARN, "objfs_init: bad vfs ops template");
return (error);
}
if (error = gfs_make_opsvec(objfs_opsvec)) {
(void) vfs_freevfsops(vfsops);
return (error);
}
if ((objfs_major = getudev()) == (major_t)-1) {
cmn_err(CE_WARN, "objfs_init: can't get unique device number");
objfs_major = 0;
}
objfs_data_init();
return (0);
}
static int
objfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
{
objfs_vfs_t *data;
dev_t dev;
if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
return (EPERM);
if (mvp->v_type != VDIR)
return (ENOTDIR);
if ((uap->flags & MS_OVERLAY) == 0 &&
(mvp->v_count > 1 || (mvp->v_flag & VROOT)))
return (EBUSY);
data = kmem_alloc(sizeof (objfs_vfs_t), KM_SLEEP);
vfsp->vfs_bsize = DEV_BSIZE;
vfsp->vfs_fstype = objfs_fstype;
do {
dev = makedevice(objfs_major,
atomic_inc_32_nv(&objfs_minor) & L_MAXMIN32);
} while (vfs_devismounted(dev));
vfs_make_fsid(&vfsp->vfs_fsid, dev, objfs_fstype);
vfsp->vfs_data = data;
vfsp->vfs_dev = dev;
data->objfs_vfs_root = objfs_create_root(vfsp);
return (0);
}
static int
objfs_unmount(vfs_t *vfsp, int flag, struct cred *cr)
{
objfs_vfs_t *data;
if (secpolicy_fs_unmount(cr, vfsp) != 0)
return (EPERM);
if (flag & MS_FORCE)
return (ENOTSUP);
ASSERT(vfsp->vfs_count >= 2);
data = vfsp->vfs_data;
if (data->objfs_vfs_root->v_count > 1)
return (EBUSY);
VN_RELE(data->objfs_vfs_root);
kmem_free(data, sizeof (objfs_vfs_t));
return (0);
}
static int
objfs_root(vfs_t *vfsp, vnode_t **vpp)
{
objfs_vfs_t *data = vfsp->vfs_data;
*vpp = data->objfs_vfs_root;
VN_HOLD(*vpp);
return (0);
}
static int
objfs_statvfs(vfs_t *vfsp, statvfs64_t *sp)
{
dev32_t d32;
int total = objfs_nobjs();
bzero(sp, sizeof (*sp));
sp->f_bsize = DEV_BSIZE;
sp->f_frsize = DEV_BSIZE;
sp->f_files = total;
sp->f_ffree = sp->f_favail = INT_MAX - total;
(void) cmpldev(&d32, vfsp->vfs_dev);
sp->f_fsid = d32;
(void) strlcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name,
sizeof (sp->f_basetype));
sp->f_flag = vf_to_stf(vfsp->vfs_flag);
sp->f_namemax = OBJFS_NAME_MAX;
(void) strlcpy(sp->f_fstr, "object", sizeof (sp->f_fstr));
return (0);
}
static const fs_operation_def_t objfs_vfstops[] = {
{ VFSNAME_MOUNT, { .vfs_mount = objfs_mount } },
{ VFSNAME_UNMOUNT, { .vfs_unmount = objfs_unmount } },
{ VFSNAME_ROOT, { .vfs_root = objfs_root } },
{ VFSNAME_STATVFS, { .vfs_statvfs = objfs_statvfs } },
{ NULL }
};