diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2015-05-07 16:10:51 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2015-05-07 16:11:04 +0000 |
commit | 6a89c8b8017eac54e4f91ba33b7b4b0967da57f5 (patch) | |
tree | 0eaf1af83ed6b987dfc07682f9321fd85593b7c6 | |
parent | 31151ba0c0d250ade7ded147921e43d2d0971fd2 (diff) | |
download | illumos-joyent-6a89c8b8017eac54e4f91ba33b7b4b0967da57f5.tar.gz |
OS-4256 centos 7 systemd stops after failing to mount sysfs
-rw-r--r-- | manifest | 1 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/mount.c | 23 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h | 154 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_syssubr.c | 192 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c | 346 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c | 628 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.files | 5 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.intel | 2 | ||||
-rw-r--r-- | usr/src/uts/intel/lx_sysfs/Makefile | 66 | ||||
-rw-r--r-- | usr/src/uts/intel/lx_sysfs/Makefile.rules | 21 |
10 files changed, 1437 insertions, 1 deletions
@@ -4564,6 +4564,7 @@ d usr/kernel/fs/amd64 0755 root sys f usr/kernel/fs/amd64/fdfs 0755 root sys f usr/kernel/fs/amd64/lx_afs 0755 root sys f usr/kernel/fs/amd64/lx_proc 0755 root sys +f usr/kernel/fs/amd64/lx_sysfs 0755 root sys f usr/kernel/fs/amd64/pcfs 0755 root sys f usr/kernel/fs/amd64/smbfs 0755 root sys d usr/kernel/kmdb 0755 root sys diff --git a/usr/src/lib/brand/lx/lx_brand/common/mount.c b/usr/src/lib/brand/lx/lx_brand/common/mount.c index 1b5df1298b..746edd9370 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/mount.c +++ b/usr/src/lib/brand/lx/lx_brand/common/mount.c @@ -80,6 +80,10 @@ mount_opt_t lx_proc_options[] = { { NULL, MOUNT_OPT_INVALID } }; +mount_opt_t lx_sysfs_options[] = { + { NULL, MOUNT_OPT_INVALID } +}; + mount_opt_t lx_tmpfs_options[] = { { LX_MNTOPT_SIZE, MOUNT_OPT_BYTESIZE }, { LX_MNTOPT_MODE, MOUNT_OPT_UINT }, @@ -714,6 +718,25 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, strcmp(sb.st_fstype, "lx_proc") == 0) { return (0); } + } else if (strcmp(fstype, "sysfs") == 0) { + /* Translate sysfs mount requests to lx_sysfs requests. */ + (void) strcpy(fstype, "lx_sysfs"); + + /* Copy in Linux mount options. */ + if (datap != NULL) { + rv = uucopystr((void *)datap, + options, sizeof (options)); + if ((rv == -1) || (rv == sizeof (options))) + return (-EFAULT); + } + lx_debug("\tlinux mount options: \"%s\"", options); + + /* Verify Linux mount options. */ + if (i_lx_opt_verify(options, lx_sysfs_options) != 0) { + lx_unsupported("unsupported sysfs mount options: %s", + options); + return (-errno); + } } else if (strcmp(fstype, "autofs") == 0) { /* Translate autofs mount requests to lx_afs requests. */ diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h b/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h new file mode 100644 index 0000000000..12483891f6 --- /dev/null +++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h @@ -0,0 +1,154 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +#ifndef _LXSYSFS_H +#define _LXSYSFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * lx_sysfs.h: declarations, data structures and macros for lx_sysfs + */ + + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/policy.h> +#include <sys/debug.h> +#include <sys/dirent.h> +#include <sys/errno.h> +#include <sys/file.h> +#include <sys/kmem.h> +#include <sys/pathname.h> +#include <sys/systm.h> +#include <sys/var.h> +#include <sys/user.h> +#include <sys/t_lock.h> +#include <sys/sysmacros.h> +#include <sys/cred.h> +#include <sys/priv.h> +#include <sys/vnode.h> +#include <sys/vfs.h> +#include <sys/statvfs.h> +#include <sys/cmn_err.h> +#include <sys/zone.h> +#include <sys/uio.h> +#include <sys/utsname.h> +#include <sys/dnlc.h> +#include <sys/atomic.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <vm/as.h> +#include <vm/anon.h> + +/* + * Convert a vnode into an lxsys_mnt_t + */ +#define VTOLXSM(vp) ((lxsys_mnt_t *)(vp)->v_vfsp->vfs_data) + +/* + * convert a vnode into an lxsys_node + */ +#define VTOLXS(vp) ((lxsys_node_t *)(vp)->v_data) + +/* + * convert a lxsys_node into a vnode + */ +#define LXSTOV(lxsnp) ((lxsnp)->lxsys_vnode) + +/* + * convert a lxsys_node into zone for fs + */ +#define LXSTOZ(lxsnp) \ + (((lxsys_mnt_t *)(lxsnp)->lxsys_vnode->v_vfsp->vfs_data)->lxsysm_zone) + +#define LXSNSIZ 256 /* max size of lx /sys file name entries */ + +/* + * Pretend that a directory entry takes 16 bytes + */ +#define LXSYS_SDSIZE 16 + +/* + * Node/file types for lx /sys files + * (directories and files contained therein). + */ +typedef enum lxsys_nodetype { + LXSYS_SYSDIR, /* /sys */ + LXSYS_FSDIR, /* /sys/fs */ + LXSYS_FS_CGROUPDIR, /* /sys/fs/cgroup */ + LXSYS_NFILES /* number of lx /sys file types */ +} lxsys_nodetype_t; + +/* + * external dirent characteristics + */ +typedef struct { + lxsys_nodetype_t d_type; + char *d_name; +} lxsys_dirent_t; + +/* + * This is the lx sysfs private data object + * which is attached to v_data in the vnode structure + */ +typedef struct lxsys_node { + lxsys_nodetype_t lxsys_type; /* type of this node */ + vnode_t *lxsys_vnode; /* vnode for the node */ + vnode_t *lxsys_parent; /* parent directory */ + vnode_t *lxsys_realvp; /* real vnode, file in dirs */ + timestruc_t lxsys_time; /* creation etc time for file */ + mode_t lxsys_mode; /* file mode bits */ + uid_t lxsys_uid; /* file owner */ + gid_t lxsys_gid; /* file group owner */ + ino_t lxsys_ino; /* node id */ +} lxsys_node_t; + +struct zone; /* forward declaration */ + +/* + * This is the lxsysfs private data object + * which is attached to vfs_data in the vfs structure + */ +typedef struct lxsys_mnt { + lxsys_node_t *lxsysm_node; /* node at root of sys mount */ + struct zone *lxsysm_zone; /* zone for this mount */ +} lxsys_mnt_t; + +extern vnodeops_t *lxsys_vnodeops; + +typedef struct mounta mounta_t; + +extern void lxsys_initnodecache(); +extern void lxsys_fininodecache(); +extern ino_t lxsys_inode(lxsys_nodetype_t); +extern ino_t lxsys_parentinode(lxsys_node_t *); +extern lxsys_node_t *lxsys_getnode(vnode_t *, lxsys_nodetype_t, proc_t *); +extern void lxsys_freenode(lxsys_node_t *); + +#ifdef __cplusplus +} +#endif + +#ifndef islower +#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) +#endif +#ifndef toupper +#define toupper(x) (islower(x) ? (x) - 'a' + 'A' : (x)) +#endif + +#endif /* _LXSYSFS_H */ diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_syssubr.c b/usr/src/uts/common/brand/lx/sysfs/lx_syssubr.c new file mode 100644 index 0000000000..7fd5de466e --- /dev/null +++ b/usr/src/uts/common/brand/lx/sysfs/lx_syssubr.c @@ -0,0 +1,192 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +/* + * lx_syssubr.c: Various functions for the /sys vnodeops. + */ + +#include <sys/varargs.h> + +#include <sys/cpuvar.h> +#include <sys/mman.h> +#include <sys/vmsystm.h> +#include <sys/prsystm.h> + +#include "lx_sysfs.h" + +#define LXSYSCACHE_NAME "lxsys_cache" + +static int lxsys_node_constructor(void *, void *, int); +static void lxsys_node_destructor(void *, void *); + +static kmem_cache_t *lxsys_node_cache; + +void +lxsys_initnodecache() +{ + lxsys_node_cache = kmem_cache_create(LXSYSCACHE_NAME, + sizeof (lxsys_node_t), 0, + lxsys_node_constructor, lxsys_node_destructor, NULL, NULL, NULL, 0); +} + +void +lxsys_fininodecache() +{ + kmem_cache_destroy(lxsys_node_cache); +} + +/* ARGSUSED */ +static int +lxsys_node_constructor(void *buf, void *un, int kmflags) +{ + lxsys_node_t *lxsnp = buf; + vnode_t *vp; + + vp = lxsnp->lxsys_vnode = vn_alloc(kmflags); + if (vp == NULL) + return (-1); + + (void) vn_setops(vp, lxsys_vnodeops); + vp->v_data = lxsnp; + + return (0); +} + +/* ARGSUSED */ +static void +lxsys_node_destructor(void *buf, void *un) +{ + lxsys_node_t *lxsnp = buf; + + vn_free(LXSTOV(lxsnp)); +} + +/* + * Calculate an inode number + * + * This takes various bits of info and munges them + * to give the inode number for an lxsys node + */ +ino_t +lxsys_inode(lxsys_nodetype_t type) +{ + return (curproc->p_zone->zone_zsched->p_pid + type); +} + +/* + * Return inode number of parent (directory) + */ +ino_t +lxsys_parentinode(lxsys_node_t *lxsnp) +{ + /* + * If the input node is the root then the parent inode + * is the mounted on inode so just return our inode number + */ + if (lxsnp->lxsys_type != LXSYS_SYSDIR) + return (VTOLXS(lxsnp->lxsys_parent)->lxsys_ino); + else + return (lxsnp->lxsys_ino); +} + +/* + * Allocate a new lxsys node + * + * This also allocates the vnode associated with it + */ +lxsys_node_t * +lxsys_getnode(vnode_t *dp, lxsys_nodetype_t type, proc_t *p) +{ + lxsys_node_t *lxsnp; + vnode_t *vp; + timestruc_t now; + + /* + * Allocate a new node. It is deallocated in vop_innactive + */ + lxsnp = kmem_cache_alloc(lxsys_node_cache, KM_SLEEP); + + /* + * Set defaults (may be overridden below) + */ + gethrestime(&now); + lxsnp->lxsys_type = type; + lxsnp->lxsys_realvp = NULL; + lxsnp->lxsys_parent = dp; + VN_HOLD(dp); + + /* Pretend files belong to sched */ + lxsnp->lxsys_time = now; + lxsnp->lxsys_uid = lxsnp->lxsys_gid = 0; + lxsnp->lxsys_ino = lxsys_inode(type); + + /* initialize the vnode data */ + vp = lxsnp->lxsys_vnode; + vn_reinit(vp); + vp->v_flag = VNOCACHE|VNOMAP|VNOSWAP|VNOMOUNT; + vp->v_vfsp = dp->v_vfsp; + + /* + * Do node specific stuff + */ + switch (type) { + case LXSYS_SYSDIR: + vp->v_flag |= VROOT; + vp->v_type = VDIR; + lxsnp->lxsys_mode = 0555; /* read-search by all */ + break; + + + case LXSYS_FSDIR: + case LXSYS_FS_CGROUPDIR: + vp->v_type = VDIR; + lxsnp->lxsys_mode = 0555; /* read-search by all */ + break; + default: + vp->v_type = VREG; + lxsnp->lxsys_mode = 0444; /* read-only by all */ + break; + } + + return (lxsnp); +} + + +/* + * Free the storage obtained from lxsys_getnode(). + */ +void +lxsys_freenode(lxsys_node_t *lxsnp) +{ + ASSERT(lxsnp != NULL); + ASSERT(LXSTOV(lxsnp) != NULL); + + /* + * delete any association with realvp + */ + if (lxsnp->lxsys_realvp != NULL) + VN_RELE(lxsnp->lxsys_realvp); + + /* + * delete any association with parent vp + */ + if (lxsnp->lxsys_parent != NULL) + VN_RELE(lxsnp->lxsys_parent); + + /* + * Release the lxsysnode. + */ + kmem_cache_free(lxsys_node_cache, lxsnp); +} diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c b/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c new file mode 100644 index 0000000000..af8add8df6 --- /dev/null +++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c @@ -0,0 +1,346 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +/* + * lxsysvfsops.c: vfs operations for lx sysfs. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/cmn_err.h> +#include <sys/cred.h> +#include <sys/debug.h> +#include <sys/errno.h> +#include <sys/proc.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/sysmacros.h> +#include <sys/systm.h> +#include <sys/var.h> +#include <sys/vfs.h> +#include <sys/vfs_opreg.h> +#include <sys/vnode.h> +#include <sys/mode.h> +#include <sys/signal.h> +#include <sys/user.h> +#include <sys/mount.h> +#include <sys/bitmap.h> +#include <sys/kmem.h> +#include <sys/policy.h> +#include <sys/modctl.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/lx_impl.h> + +#include "lx_sysfs.h" + +/* Module level parameters */ +static int lxsysfstype; +static dev_t lxsysdev; +static kmutex_t lxsys_mount_lock; + +static int lxsys_mount(vfs_t *, vnode_t *, mounta_t *, cred_t *); +static int lxsys_unmount(vfs_t *, int, cred_t *); +static int lxsys_root(vfs_t *, vnode_t **); +static int lxsys_statvfs(vfs_t *, statvfs64_t *); +static int lxsys_init(int, char *); + +static vfsdef_t vfw = { + VFSDEF_VERSION, + "lx_sysfs", + lxsys_init, + VSW_ZMOUNT, + NULL +}; + +/* + * Module linkage information for the kernel. + */ +extern struct mod_ops mod_fsops; + +static struct modlfs modlfs = { + &mod_fsops, "lx brand sysfs", &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) +{ + int retval; + + /* + * attempt to unload the module + */ + if ((retval = mod_remove(&modlinkage)) != 0) + goto done; + + /* + * destroy lxsys_node cache + */ + lxsys_fininodecache(); + + /* + * clean out the vfsops and vnodeops + */ + (void) vfs_freevfsops_by_type(lxsysfstype); + vn_freevnodeops(lxsys_vnodeops); + + mutex_destroy(&lxsys_mount_lock); +done: + return (retval); +} + +static int +lxsys_init(int fstype, char *name) +{ + static const fs_operation_def_t lxsys_vfsops_template[] = { + VFSNAME_MOUNT, { .vfs_mount = lxsys_mount }, + VFSNAME_UNMOUNT, { .vfs_unmount = lxsys_unmount }, + VFSNAME_ROOT, { .vfs_root = lxsys_root }, + VFSNAME_STATVFS, { .vfs_statvfs = lxsys_statvfs }, + NULL, NULL + }; + extern const fs_operation_def_t lxsys_vnodeops_template[]; + int error; + major_t dev; + + lxsysfstype = fstype; + ASSERT(lxsysfstype != 0); + + mutex_init(&lxsys_mount_lock, NULL, MUTEX_DEFAULT, NULL); + + /* + * Associate VFS ops vector with this fstype. + */ + error = vfs_setfsops(fstype, lxsys_vfsops_template, NULL); + if (error != 0) { + cmn_err(CE_WARN, "lxsys_init: bad vfs ops template"); + return (error); + } + + /* + * Set up vnode ops vector too. + */ + error = vn_make_ops(name, lxsys_vnodeops_template, &lxsys_vnodeops); + if (error != 0) { + (void) vfs_freevfsops_by_type(fstype); + cmn_err(CE_WARN, "lxsys_init: bad vnode ops template"); + return (error); + } + + /* + * Assign a unique "device" number (used by stat(2)). + */ + if ((dev = getudev()) == (major_t)-1) { + cmn_err(CE_WARN, "lxsys_init: can't get unique device number"); + dev = 0; + } + + /* + * Make the pseudo device + */ + lxsysdev = makedevice(dev, 0); + + /* + * Initialise cache for lxsys_nodes + */ + lxsys_initnodecache(); + + return (0); +} + +static int +lxsys_mount(vfs_t *vfsp, vnode_t *mvp, mounta_t *uap, cred_t *cr) +{ + lxsys_mnt_t *lxsys_mnt; + zone_t *zone = curproc->p_zone; + + /* + * must be root to mount + */ + if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) + return (EPERM); + + /* + * mount point must be a directory + */ + if (mvp->v_type != VDIR) + return (ENOTDIR); + + if (zone == global_zone) { + zone_t *mntzone; + + mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); + zone_rele(mntzone); + if (zone != mntzone) + return (EBUSY); + } + + /* + * Having the resource be anything but "lxsys" doesn't make sense + */ + vfs_setresource(vfsp, "lxsys", 0); + + lxsys_mnt = kmem_alloc(sizeof (*lxsys_mnt), KM_SLEEP); + + mutex_enter(&lxsys_mount_lock); + + /* + * Ensure we don't allow overlaying mounts + */ + mutex_enter(&mvp->v_lock); + if ((uap->flags & MS_OVERLAY) == 0 && + (mvp->v_count > 1 || (mvp->v_flag & VROOT))) { + mutex_exit(&mvp->v_lock); + mutex_exit(&lxsys_mount_lock); + kmem_free(lxsys_mnt, sizeof ((*lxsys_mnt))); + return (EBUSY); + } + mutex_exit(&mvp->v_lock); + + /* + * allocate the first vnode + */ + zone_hold(lxsys_mnt->lxsysm_zone = zone); + + /* Arbitrarily set the parent vnode to the mounted over directory */ + lxsys_mnt->lxsysm_node = lxsys_getnode(mvp, LXSYS_SYSDIR, NULL); + + /* Correctly set the fs for the root node */ + lxsys_mnt->lxsysm_node->lxsys_vnode->v_vfsp = vfsp; + + vfs_make_fsid(&vfsp->vfs_fsid, lxsysdev, lxsysfstype); + vfsp->vfs_bsize = DEV_BSIZE; + vfsp->vfs_fstype = lxsysfstype; + vfsp->vfs_data = (caddr_t)lxsys_mnt; + vfsp->vfs_dev = lxsysdev; + + mutex_exit(&lxsys_mount_lock); + + return (0); +} + +static int +lxsys_unmount(vfs_t *vfsp, int flag, cred_t *cr) +{ + lxsys_mnt_t *lxsys_mnt = (lxsys_mnt_t *)vfsp->vfs_data; + vnode_t *vp; + int count; + + ASSERT(lxsys_mnt != NULL); + vp = LXSTOV(lxsys_mnt->lxsysm_node); + + mutex_enter(&lxsys_mount_lock); + + /* + * must be root to unmount + */ + if (secpolicy_fs_unmount(cr, vfsp) != 0) { + mutex_exit(&lxsys_mount_lock); + return (EPERM); + } + + /* + * forced unmount is not supported by this file system + */ + if (flag & MS_FORCE) { + mutex_exit(&lxsys_mount_lock); + return (ENOTSUP); + } + + /* + * Ensure that no vnodes are in use on this mount point. + */ + mutex_enter(&vp->v_lock); + count = vp->v_count; + mutex_exit(&vp->v_lock); + if (count > 1) { + mutex_exit(&lxsys_mount_lock); + return (EBUSY); + } + + + /* + * purge the dnlc cache for vnode entries + * associated with this file system + */ + count = dnlc_purge_vfsp(vfsp, 0); + + /* + * free up the lxsysnode + */ + lxsys_freenode(lxsys_mnt->lxsysm_node); + zone_rele(lxsys_mnt->lxsysm_zone); + kmem_free(lxsys_mnt, sizeof (*lxsys_mnt)); + + mutex_exit(&lxsys_mount_lock); + + return (0); +} + +static int +lxsys_root(vfs_t *vfsp, vnode_t **vpp) +{ + lxsys_node_t *lxsnp = ((lxsys_mnt_t *)vfsp->vfs_data)->lxsysm_node; + vnode_t *vp = LXSTOV(lxsnp); + + VN_HOLD(vp); + *vpp = vp; + return (0); +} + +static int +lxsys_statvfs(vfs_t *vfsp, statvfs64_t *sp) +{ + dev32_t d32; + + bzero((caddr_t)sp, sizeof (*sp)); + sp->f_bsize = DEV_BSIZE; + sp->f_frsize = DEV_BSIZE; + sp->f_blocks = (fsblkcnt64_t)0; + sp->f_bfree = (fsblkcnt64_t)0; + sp->f_bavail = (fsblkcnt64_t)0; + sp->f_files = (fsfilcnt64_t)3; + sp->f_ffree = (fsfilcnt64_t)0; /* none */ + sp->f_favail = (fsfilcnt64_t)0; /* none */ + (void) cmpldev(&d32, vfsp->vfs_dev); + sp->f_fsid = d32; + /* It is guaranteed that vsw_name will fit in f_basetype */ + (void) strcpy(sp->f_basetype, vfssw[lxsysfstype].vsw_name); + sp->f_flag = vf_to_stf(vfsp->vfs_flag); + sp->f_namemax = 64; /* quite arbitrary */ + bzero(sp->f_fstr, sizeof (sp->f_fstr)); + + /* We know f_fstr is 32 chars */ + (void) strcpy(sp->f_fstr, "/sys"); + (void) strcpy(&sp->f_fstr[6], "/sys"); + + return (0); +} diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c b/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c new file mode 100644 index 0000000000..29ad2dbb97 --- /dev/null +++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c @@ -0,0 +1,628 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +/* + * lx_sysfs -- a Linux-compatible /sys for the LX brand + */ + +#include <vm/seg_vn.h> +#include <sys/sdt.h> +#include <sys/strlog.h> +#include <sys/stropts.h> +#include <sys/cmn_err.h> +#include <sys/lx_brand.h> +#include <sys/x86_archext.h> +#include <sys/archsystm.h> +#include <sys/fp.h> +#include <sys/pool_pset.h> +#include <sys/pset.h> +#include <sys/zone.h> +#include <sys/pghw.h> +#include <sys/vfs_opreg.h> +#include <sys/param.h> +#include <sys/utsname.h> +#include <sys/lx_misc.h> +#include <sys/brand.h> +#include <sys/cred_impl.h> +#include <sys/tihdr.h> + +#include "lx_sysfs.h" + +/* + * Pointer to the vnode ops vector for this fs. + * This is instantiated in lxsys_init() in lx_sysvfsops.c + */ +vnodeops_t *lxsys_vnodeops; + +static int lxsys_open(vnode_t **, int, cred_t *, caller_context_t *); +static int lxsys_close(vnode_t *, int, int, offset_t, cred_t *, + caller_context_t *); +static int lxsys_read(vnode_t *, uio_t *, int, cred_t *, caller_context_t *); +static int lxsys_getattr(vnode_t *, vattr_t *, int, cred_t *, + caller_context_t *); +static int lxsys_access(vnode_t *, int, int, cred_t *, caller_context_t *); +static int lxsys_lookup(vnode_t *, char *, vnode_t **, + pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *, + pathname_t *); +static int lxsys_readdir(vnode_t *, uio_t *, cred_t *, int *, + caller_context_t *, int); +static int lxsys_readlink(vnode_t *, uio_t *, cred_t *, caller_context_t *); +static int lxsys_cmp(vnode_t *, vnode_t *, caller_context_t *); +static int lxsys_realvp(vnode_t *, vnode_t **, caller_context_t *); +static int lxsys_sync(void); +static void lxsys_inactive(vnode_t *, cred_t *, caller_context_t *); + +static vnode_t *lxsys_lookup_sysdir(vnode_t *, char *); +static vnode_t *lxsys_lookup_fsdir(vnode_t *, char *); +static vnode_t *lxsys_lookup_fs_cgroupdir(vnode_t *, char *); + +static int lxsys_readdir_sysdir(lxsys_node_t *, uio_t *, int *); +static int lxsys_readdir_fsdir(lxsys_node_t *, uio_t *, int *); +static int lxsys_readdir_fs_cgroupdir(lxsys_node_t *, uio_t *, int *); + +/* + * The lx /sys vnode operations vector + */ +const fs_operation_def_t lxsys_vnodeops_template[] = { + VOPNAME_OPEN, { .vop_open = lxsys_open }, + VOPNAME_CLOSE, { .vop_close = lxsys_close }, + VOPNAME_READ, { .vop_read = lxsys_read }, + VOPNAME_GETATTR, { .vop_getattr = lxsys_getattr }, + VOPNAME_ACCESS, { .vop_access = lxsys_access }, + VOPNAME_LOOKUP, { .vop_lookup = lxsys_lookup }, + VOPNAME_READDIR, { .vop_readdir = lxsys_readdir }, + VOPNAME_READLINK, { .vop_readlink = lxsys_readlink }, + VOPNAME_FSYNC, { .error = lxsys_sync }, + VOPNAME_SEEK, { .error = lxsys_sync }, + VOPNAME_INACTIVE, { .vop_inactive = lxsys_inactive }, + VOPNAME_CMP, { .vop_cmp = lxsys_cmp }, + VOPNAME_REALVP, { .vop_realvp = lxsys_realvp }, + NULL, NULL +}; + + +/* + * file contents of an lx /sys directory. + */ +static lxsys_dirent_t sysdir[] = { + { LXSYS_FSDIR, "fs" } +}; + +#define SYSDIRFILES (sizeof (sysdir) / sizeof (sysdir[0])) + +/* + * contents of lx /sys/fs directory + */ +static lxsys_dirent_t fsdir[] = { + { LXSYS_FS_CGROUPDIR, "cgroup" } +}; + +#define FSDIRFILES (sizeof (fsdir) / sizeof (fsdir[0])) + +/* + * contents of lx /sys/fs/cgroup directory + */ +static lxsys_dirent_t cgroupdir[] = { +}; + +#define CGROUPDIRFILES 0 + +/* + * lxsys_open(): Vnode operation for VOP_OPEN() + */ +static int +lxsys_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) +{ + vnode_t *vp = *vpp; + lxsys_node_t *lxsnp = VTOLXS(vp); + vnode_t *rvp; + int error = 0; + + /* + * We only allow reading in this file system + */ + if (flag & FWRITE) + return (EROFS); + + /* + * If we are opening an underlying file only allow regular files, + * reject the open for anything else. + * Just do it if we are opening the current or root directory. + */ + if (lxsnp->lxsys_realvp != NULL) { + rvp = lxsnp->lxsys_realvp; + + /* + * Need to hold rvp since VOP_OPEN() may release it. + */ + VN_HOLD(rvp); + error = VOP_OPEN(&rvp, flag, cr, ct); + if (error) { + VN_RELE(rvp); + } else { + *vpp = rvp; + VN_RELE(vp); + } + } + + return (error); +} + + +/* + * lxsys_close(): Vnode operation for VOP_CLOSE() + */ +/* ARGSUSED */ +static int +lxsys_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, + caller_context_t *ct) +{ + return (0); +} + +/* + * Array of lookup functions, indexed by lx /sys file type. + */ +static vnode_t *(*lxsys_lookup_function[LXSYS_NFILES])() = { + lxsys_lookup_sysdir, /* /sys */ + lxsys_lookup_fsdir, /* /sys/fs */ + lxsys_lookup_fs_cgroupdir, /* /sys/fs/cgroup */ +}; + +/* + * Array of readdir functions, indexed by /sys file type. + */ +static int (*lxsys_readdir_function[LXSYS_NFILES])() = { + lxsys_readdir_sysdir, /* /sys */ + lxsys_readdir_fsdir, /* /sys/fs */ + lxsys_readdir_fs_cgroupdir, /* /sys/fs/cgroup */ +}; + + +/* + * lxsys_read(): Vnode operation for VOP_READ() + * All we currently have in this fs are directories. + */ +/* ARGSUSED */ +static int +lxsys_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, + caller_context_t *ct) +{ + lxsys_node_t *lxsnp = VTOLXS(vp); + lxsys_nodetype_t type = lxsnp->lxsys_type; + + ASSERT(type < LXSYS_NFILES); + return (EISDIR); +} + +/* + * lxsys_getattr(): Vnode operation for VOP_GETATTR() + */ +static int +lxsys_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, + caller_context_t *ct) +{ + register lxsys_node_t *lxsnp = VTOLXS(vp); + int error; + + /* + * Return attributes of underlying vnode if ATTR_REAL + * + * but keep fd files with the symlink permissions + */ + if (lxsnp->lxsys_realvp != NULL && (flags & ATTR_REAL)) { + vnode_t *rvp = lxsnp->lxsys_realvp; + + /* + * limit attribute information to owner or root + */ + if ((error = VOP_ACCESS(rvp, 0, 0, cr, ct)) != 0) { + return (error); + } + + /* + * now its attributes + */ + if ((error = VOP_GETATTR(rvp, vap, flags, cr, ct)) != 0) { + return (error); + } + + return (0); + } + + /* Default attributes, that may be overridden below */ + bzero(vap, sizeof (*vap)); + vap->va_atime = vap->va_mtime = vap->va_ctime = lxsnp->lxsys_time; + vap->va_nlink = 1; + vap->va_type = vp->v_type; + vap->va_mode = lxsnp->lxsys_mode; + vap->va_fsid = vp->v_vfsp->vfs_dev; + vap->va_blksize = DEV_BSIZE; + vap->va_uid = lxsnp->lxsys_uid; + vap->va_gid = lxsnp->lxsys_gid; + vap->va_nodeid = lxsnp->lxsys_ino; + + vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size); + return (0); +} + +/* + * lxsys_access(): Vnode operation for VOP_ACCESS() + */ +static int +lxsys_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) +{ + lxsys_node_t *lxsnp = VTOLXS(vp); + int shift = 0; + + /* + * Although our lx sysfs is basically a read only file system, Linux + * expects it to be writable so we can't just error if (mode & VWRITE). + */ + + if (lxsnp->lxsys_realvp != NULL) { + /* + * For these we use the underlying vnode's accessibility. + */ + return (VOP_ACCESS(lxsnp->lxsys_realvp, mode, flags, cr, ct)); + } + + /* If user is root allow access regardless of permission bits */ + if (secpolicy_proc_access(cr) == 0) + return (0); + + /* + * Access check is based on only one of owner, group, public. If not + * owner, then check group. If not a member of the group, then check + * public access. + */ + if (crgetuid(cr) != lxsnp->lxsys_uid) { + shift += 3; + if (!groupmember((uid_t)lxsnp->lxsys_gid, cr)) + shift += 3; + } + + mode &= ~(lxsnp->lxsys_mode << shift); + + if (mode == 0) + return (0); + + return (EACCES); +} + +/* + * lxsys_lookup(): Vnode operation for VOP_LOOKUP() + */ +/* ARGSUSED */ +static int +lxsys_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp, + int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, + int *direntflags, pathname_t *realpnp) +{ + lxsys_node_t *lxsnp = VTOLXS(dp); + lxsys_nodetype_t type = lxsnp->lxsys_type; + int error; + + ASSERT(dp->v_type == VDIR); + ASSERT(type < LXSYS_NFILES); + + /* + * restrict lookup permission to owner or root + */ + if ((error = lxsys_access(dp, VEXEC, 0, cr, ct)) != 0) { + return (error); + } + + /* + * Just return the parent vnode if that's where we are trying to go. + */ + if (strcmp(comp, "..") == 0) { + VN_HOLD(lxsnp->lxsys_parent); + *vpp = lxsnp->lxsys_parent; + return (0); + } + + /* + * Special handling for directory searches. Note: null component name + * denotes that the current directory is being searched. + */ + if ((dp->v_type == VDIR) && (*comp == '\0' || strcmp(comp, ".") == 0)) { + VN_HOLD(dp); + *vpp = dp; + return (0); + } + + *vpp = (lxsys_lookup_function[type](dp, comp)); + return ((*vpp == NULL) ? ENOENT : 0); +} + +/* + * Do a sequential search on the given directory table + */ +static vnode_t * +lxsys_lookup_common(vnode_t *dp, char *comp, proc_t *p, + lxsys_dirent_t *dirtab, int dirtablen) +{ + lxsys_node_t *lxsnp; + int count; + + for (count = 0; count < dirtablen; count++) { + if (strcmp(dirtab[count].d_name, comp) == 0) { + lxsnp = lxsys_getnode(dp, dirtab[count].d_type, p); + dp = LXSTOV(lxsnp); + ASSERT(dp != NULL); + return (dp); + } + } + return (NULL); +} + +static vnode_t * +lxsys_lookup_sysdir(vnode_t *dp, char *comp) +{ + ASSERT(VTOLXS(dp)->lxsys_type == LXSYS_SYSDIR); + return (lxsys_lookup_common(dp, comp, NULL, sysdir, SYSDIRFILES)); +} + +static vnode_t * +lxsys_lookup_fsdir(vnode_t *dp, char *comp) +{ + ASSERT(VTOLXS(dp)->lxsys_type == LXSYS_FSDIR); + return (lxsys_lookup_common(dp, comp, NULL, fsdir, FSDIRFILES)); +} + +static vnode_t * +lxsys_lookup_fs_cgroupdir(vnode_t *dp, char *comp) +{ + ASSERT(VTOLXS(dp)->lxsys_type == LXSYS_FS_CGROUPDIR); + return (lxsys_lookup_common(dp, comp, NULL, cgroupdir, CGROUPDIRFILES)); +} + +/* + * lxsys_readdir(): Vnode operation for VOP_READDIR() + */ +/* ARGSUSED */ +static int +lxsys_readdir(vnode_t *dp, uio_t *uiop, cred_t *cr, int *eofp, + caller_context_t *ct, int flags) +{ + lxsys_node_t *lxsnp = VTOLXS(dp); + lxsys_nodetype_t type = lxsnp->lxsys_type; + ssize_t uresid; + off_t uoffset; + int error; + + ASSERT(dp->v_type == VDIR); + ASSERT(type < LXSYS_NFILES); + + /* + * restrict readdir permission to owner or root + */ + if ((error = lxsys_access(dp, VREAD, 0, cr, ct)) != 0) + return (error); + + uoffset = uiop->uio_offset; + uresid = uiop->uio_resid; + + /* can't do negative reads */ + if (uoffset < 0 || uresid <= 0) + return (EINVAL); + + /* can't read directory entries that don't exist! */ + if (uoffset % LXSYS_SDSIZE) + return (ENOENT); + + return (lxsys_readdir_function[lxsnp->lxsys_type](lxsnp, uiop, eofp)); +} + +/* + * This has the common logic for returning directory entries + */ +static int +lxsys_readdir_common(lxsys_node_t *lxsnp, uio_t *uiop, int *eofp, + lxsys_dirent_t *dirtab, int dirtablen) +{ + /* bp holds one dirent64 structure */ + longlong_t bp[DIRENT64_RECLEN(LXSNSIZ) / sizeof (longlong_t)]; + dirent64_t *dirent = (dirent64_t *)bp; + ssize_t oresid; /* save a copy for testing later */ + ssize_t uresid; + + oresid = uiop->uio_resid; + + /* clear out the dirent buffer */ + bzero(bp, sizeof (bp)); + + /* + * Satisfy user request + */ + while ((uresid = uiop->uio_resid) > 0) { + int dirindex; + off_t uoffset; + int reclen; + int error; + + uoffset = uiop->uio_offset; + dirindex = (uoffset / LXSYS_SDSIZE) - 2; + + if (uoffset == 0) { + + dirent->d_ino = lxsnp->lxsys_ino; + dirent->d_name[0] = '.'; + dirent->d_name[1] = '\0'; + reclen = DIRENT64_RECLEN(1); + + } else if (uoffset == LXSYS_SDSIZE) { + + dirent->d_ino = lxsys_parentinode(lxsnp); + dirent->d_name[0] = '.'; + dirent->d_name[1] = '.'; + dirent->d_name[2] = '\0'; + reclen = DIRENT64_RECLEN(2); + + } else if (dirindex < dirtablen) { + int slen = strlen(dirtab[dirindex].d_name); + + dirent->d_ino = lxsys_inode(dirtab[dirindex].d_type); + + ASSERT(slen < LXSNSIZ); + (void) strcpy(dirent->d_name, dirtab[dirindex].d_name); + reclen = DIRENT64_RECLEN(slen); + + } else { + /* Run out of table entries */ + if (eofp) { + *eofp = 1; + } + return (0); + } + + dirent->d_off = (off64_t)(uoffset + LXSYS_SDSIZE); + dirent->d_reclen = (ushort_t)reclen; + + /* + * if the size of the data to transfer is greater + * that that requested then we can't do it this transfer. + */ + if (reclen > uresid) { + /* + * Error if no entries have been returned yet. + */ + if (uresid == oresid) { + return (EINVAL); + } + break; + } + + /* + * uiomove() updates both uiop->uio_resid and uiop->uio_offset + * by the same amount. But we want uiop->uio_offset to change + * in increments of LXSYS_SDSIZE, which is different from the + * number of bytes being returned to the user. So we set + * uiop->uio_offset separately, ignoring what uiomove() does. + */ + if ((error = uiomove((caddr_t)dirent, reclen, UIO_READ, + uiop)) != 0) + return (error); + + uiop->uio_offset = uoffset + LXSYS_SDSIZE; + } + + /* Have run out of space, but could have just done last table entry */ + if (eofp) { + *eofp = (uiop->uio_offset >= ((dirtablen+2) * LXSYS_SDSIZE)) ? + 1 : 0; + } + return (0); +} + +static int +lxsys_readdir_sysdir(lxsys_node_t *lxsnp, uio_t *uiop, int *eofp) +{ + ASSERT(lxsnp->lxsys_type == LXSYS_SYSDIR); + return (lxsys_readdir_common(lxsnp, uiop, eofp, sysdir, SYSDIRFILES)); +} + +static int +lxsys_readdir_fsdir(lxsys_node_t *lxsnp, uio_t *uiop, int *eofp) +{ + ASSERT(lxsnp->lxsys_type == LXSYS_FSDIR); + return (lxsys_readdir_common(lxsnp, uiop, eofp, fsdir, FSDIRFILES)); +} + +static int +lxsys_readdir_fs_cgroupdir(lxsys_node_t *lxsnp, uio_t *uiop, int *eofp) +{ + ASSERT(lxsnp->lxsys_type == LXSYS_FS_CGROUPDIR); + return (lxsys_readdir_common(lxsnp, uiop, eofp, cgroupdir, + CGROUPDIRFILES)); +} + +/* + * lxsys_readlink(): Vnode operation for VOP_READLINK() + */ +/* ARGSUSED */ +static int +lxsys_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct) +{ + return (EINVAL); +} + + +/* + * lxsys_inactive(): Vnode operation for VOP_INACTIVE() + * Vnode is no longer referenced, deallocate the file + * and all its resources. + */ +/* ARGSUSED */ +static void +lxsys_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) +{ + lxsys_freenode(VTOLXS(vp)); +} + +/* + * lxsys_sync(): Vnode operation for VOP_SYNC() + */ +static int +lxsys_sync() +{ + /* + * Nothing to sync but this function must never fail + */ + return (0); +} + +/* + * lxsys_cmp(): Vnode operation for VOP_CMP() + */ +static int +lxsys_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) +{ + vnode_t *rvp; + + while (vn_matchops(vp1, lxsys_vnodeops) && + (rvp = VTOLXS(vp1)->lxsys_realvp) != NULL) { + vp1 = rvp; + } + + while (vn_matchops(vp2, lxsys_vnodeops) && + (rvp = VTOLXS(vp2)->lxsys_realvp) != NULL) { + vp2 = rvp; + } + + if (vn_matchops(vp1, lxsys_vnodeops) || + vn_matchops(vp2, lxsys_vnodeops)) + return (vp1 == vp2); + return (VOP_CMP(vp1, vp2, ct)); +} + +/* + * lxsys_realvp(): Vnode operation for VOP_REALVP() + */ +static int +lxsys_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct) +{ + vnode_t *rvp; + + if ((rvp = VTOLXS(vp)->lxsys_realvp) != NULL) { + vp = rvp; + if (VOP_REALVP(vp, &rvp, ct) == 0) + vp = rvp; + } + + *vpp = vp; + return (0); +} diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index e2fd605916..add15d039a 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -105,6 +105,11 @@ LX_PROC_OBJS += \ lx_prvfsops.o \ lx_prvnops.o +LX_SYS_OBJS += \ + lx_syssubr.o \ + lx_sysvfsops.o \ + lx_sysvnops.o + LX_AUTOFS_OBJS += \ lx_autofs.o diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel index 86f7330f69..13c235dd5b 100644 --- a/usr/src/uts/intel/Makefile.intel +++ b/usr/src/uts/intel/Makefile.intel @@ -538,7 +538,7 @@ SCHED_KMODS += IA RT TS RT_DPTBL TS_DPTBL FSS FX FX_DPTBL SDC # FS_KMODS += autofs cachefs ctfs dcfs dev devfs fdfs fifofs hsfs hyprlofs FS_KMODS += lofs lx_afs lx_proc lxprocfs mntfs namefs nfs objfs zfs zut -FS_KMODS += pcfs procfs sockfs specfs tmpfs udfs ufs sharefs +FS_KMODS += pcfs procfs sockfs specfs tmpfs udfs ufs sharefs lx_sysfs FS_KMODS += smbfs bootfs # diff --git a/usr/src/uts/intel/lx_sysfs/Makefile b/usr/src/uts/intel/lx_sysfs/Makefile new file mode 100644 index 0000000000..ef442fc22a --- /dev/null +++ b/usr/src/uts/intel/lx_sysfs/Makefile @@ -0,0 +1,66 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Joyent, Inc. +# + +UTSBASE = ../.. + +LX_CMN = $(SRC)/common/brand/lx + +MODULE = lx_sysfs +OBJECTS = $(LX_SYS_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(LX_SYS_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_FS_DIR)/$(MODULE) + +INC_PATH += -I$(UTSBASE)/common/brand/lx -I$(LX_CMN) + +include $(UTSBASE)/intel/Makefile.intel + +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +CFLAGS += $(CCVERBOSE) + +LDFLAGS += -dy -Nbrand/lx_brand + +# +# For now, disable these lint checks; maintainers should endeavor +# to investigate and remove these for maximum lint coverage. +# Please do not carry these forward to new Makefiles. +# +# XXX JJ +# LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW +# LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +include $(UTSBASE)/intel/Makefile.targ + +include $(UTSBASE)/intel/lx_sysfs/Makefile.rules diff --git a/usr/src/uts/intel/lx_sysfs/Makefile.rules b/usr/src/uts/intel/lx_sysfs/Makefile.rules new file mode 100644 index 0000000000..c9d4c28f85 --- /dev/null +++ b/usr/src/uts/intel/lx_sysfs/Makefile.rules @@ -0,0 +1,21 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2015 Joyent, Inc. All rights reserved. +# + +$(OBJS_DIR)/%.o: $(UTSBASE)/common/brand/lx/sysfs/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/brand/lx/sysfs/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) |