/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * CTFS routines for the /system/contract//template vnode. */ /* * ctfs_create_tmplnode * * Creates a new template and tdirnode, and returns the tdirnode. */ vnode_t * ctfs_create_tmplnode(vnode_t *pvp) { vnode_t *vp; ctfs_tmplnode_t *tmplnode; ASSERT(gfs_file_index(pvp) < ct_ntypes); vp = gfs_file_create(sizeof (ctfs_tmplnode_t), pvp, ctfs_ops_tmpl); tmplnode = vp->v_data; tmplnode->ctfs_tmn_tmpl = ct_types[gfs_file_index(pvp)]->ct_type_default(); return (vp); } /* * ctfs_tmpl_open - VOP_OPEN entry point * * Just ensures the right mode bits are set. */ /* ARGSUSED */ static int ctfs_tmpl_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) { if (flag != (FREAD | FWRITE | FOFFMAX)) return (EINVAL); return (0); } /* * ctfs_tmpl_getattr - VOP_GETATTR entry point */ /* ARGSUSED */ static int ctfs_tmpl_getattr( vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, caller_context_t *ct) { vap->va_type = VREG; vap->va_mode = 0666; vap->va_nlink = 1; vap->va_size = 0; vap->va_ctime.tv_sec = vp->v_vfsp->vfs_mtime; vap->va_ctime.tv_nsec = 0; vap->va_atime = vap->va_mtime = vap->va_ctime; ctfs_common_getattr(vp, vap); return (0); } /* * ctfs_tmpl_ioctl - VOP_IOCTL entry point * * All the ct_tmpl_*(3contract) interfaces point here. */ /* ARGSUSED */ static int ctfs_tmpl_ioctl( vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp, caller_context_t *ct) { ctfs_tmplnode_t *tmplnode = vp->v_data; ct_param_t param; STRUCT_DECL(ct_param, uarg); ctid_t ctid; uint32_t local_ctpm_size; int error; STRUCT_INIT(uarg, flag); switch (cmd) { case CT_TACTIVATE: ASSERT(tmplnode->ctfs_tmn_tmpl != NULL); ctmpl_activate(tmplnode->ctfs_tmn_tmpl); break; case CT_TCLEAR: ASSERT(tmplnode->ctfs_tmn_tmpl != NULL); ctmpl_clear(tmplnode->ctfs_tmn_tmpl); break; case CT_TCREATE: ASSERT(tmplnode->ctfs_tmn_tmpl != NULL); error = ctmpl_create(tmplnode->ctfs_tmn_tmpl, &ctid); if (error) return (error); *rvalp = ctid; break; case CT_TSET: if (copyin((void *)arg, STRUCT_BUF(uarg), STRUCT_SIZE(uarg))) return (EFAULT); param.ctpm_id = STRUCT_FGET(uarg, ctpm_id); param.ctpm_size = STRUCT_FGET(uarg, ctpm_size); if (param.ctpm_size > CT_PARAM_MAX_SIZE || param.ctpm_size == 0) return (EINVAL); param.ctpm_value = kmem_alloc(param.ctpm_size, KM_SLEEP); if (copyin(STRUCT_FGETP(uarg, ctpm_value), param.ctpm_value, param.ctpm_size)) return (EFAULT); error = ctmpl_set(tmplnode->ctfs_tmn_tmpl, ¶m, cr); kmem_free(param.ctpm_value, param.ctpm_size); return (error); case CT_TGET: if (copyin((void *)arg, STRUCT_BUF(uarg), STRUCT_SIZE(uarg))) return (EFAULT); param.ctpm_id = STRUCT_FGET(uarg, ctpm_id); param.ctpm_size = STRUCT_FGET(uarg, ctpm_size); if (param.ctpm_size > CT_PARAM_MAX_SIZE) param.ctpm_size = CT_PARAM_MAX_SIZE; if (param.ctpm_size == 0) return (EINVAL); local_ctpm_size = param.ctpm_size; param.ctpm_value = kmem_alloc(param.ctpm_size, KM_SLEEP); error = ctmpl_get(tmplnode->ctfs_tmn_tmpl, ¶m); STRUCT_FSET(uarg, ctpm_size, param.ctpm_size); if (!error && (copyout(param.ctpm_value, STRUCT_FGETP(uarg, ctpm_value), MIN(local_ctpm_size, param.ctpm_size))) || copyout(STRUCT_BUF(uarg), (void *)arg, STRUCT_SIZE(uarg))) error = EFAULT; kmem_free(param.ctpm_value, local_ctpm_size); return (error); default: return (EINVAL); } return (0); } /* * ctfs_tmpl_inactive - VOP_INACTIVE entry point */ /* ARGSUSED */ static void ctfs_tmpl_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) { ctfs_tmplnode_t *tmplnode; if ((tmplnode = gfs_file_inactive(vp)) != NULL) { ctmpl_free(tmplnode->ctfs_tmn_tmpl); kmem_free(tmplnode, sizeof (ctfs_tmplnode_t)); } } const fs_operation_def_t ctfs_tops_tmpl[] = { { VOPNAME_OPEN, { .vop_open = ctfs_tmpl_open } }, { VOPNAME_CLOSE, { .vop_close = ctfs_close } }, { VOPNAME_IOCTL, { .vop_ioctl = ctfs_tmpl_ioctl } }, { VOPNAME_GETATTR, { .vop_getattr = ctfs_tmpl_getattr } }, { VOPNAME_ACCESS, { .vop_access = ctfs_access_readwrite } }, { VOPNAME_READDIR, { .error = fs_notdir } }, { VOPNAME_LOOKUP, { .error = fs_notdir } }, { VOPNAME_INACTIVE, { .vop_inactive = ctfs_tmpl_inactive } }, { NULL, NULL } };