2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <libuvfs_impl.h>
2N/A
2N/A#include <umem.h>
2N/A#include <unistd.h>
2N/A#include <sys/types.h>
2N/A#include <sys/types32.h>
2N/A#include <sys/mkdev.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <strings.h>
2N/A#include <pthread.h>
2N/A#include <atomic.h>
2N/A
2N/Astatic umem_cache_t *libuvfs_fs_cache;
2N/A
2N/Auint32_t libuvfs_umem_alloc_failures = 0;
2N/Auint32_t libuvfs_umem_alloc_max_failures = LIBUVFS_UMEM_ALLOC_MAX_FAILURES;
2N/Auint32_t libuvfs_umem_alloc_failure_sleep = LIBUVFS_UMEM_ALLOC_FAILURE_SLEEP;
2N/A
2N/Astatic libuvfs_callback_reg_t libuvfs_default_callbacks[] = {
2N/A {UVFS_CB_VOP_FSYNC, libuvfs_default_success},
2N/A {NULL, NULL},
2N/A};
2N/A
2N/Astatic void
2N/Alibuvfs_init_callbacks(libuvfs_fs_t *fs)
2N/A{
2N/A const libuvfs_callback_reg_t *reg;
2N/A int i;
2N/A
2N/A for (i = 0; i < UVFS_CB_NUM_OPS; i++)
2N/A fs->fs_callback[i].lcr_callback = NULL;
2N/A
2N/A for (reg = libuvfs_default_callbacks; reg->lcr_callback; reg++)
2N/A fs->fs_callback[reg->lcr_optag] = *reg;
2N/A}
2N/A
2N/Astatic void
2N/Alibuvfs_fs_rand(libuvfs_fs_t *fs)
2N/A{
2N/A int f;
2N/A
2N/A fs->fs_fid_random = rand();
2N/A f = open("/dev/random", O_RDONLY);
2N/A if (f >= 0) {
2N/A uint64_t better;
2N/A
2N/A (void) read(f, &better, sizeof (better));
2N/A (void) close(f);
2N/A
2N/A fs->fs_fid_random ^= better;
2N/A }
2N/A}
2N/A
2N/Alibuvfs_fs_t *
2N/Alibuvfs_create_fs(libuvfs_version_t version, uint64_t fsid)
2N/A{
2N/A libuvfs_fs_t *fs;
2N/A
2N/A if (version != LIBUVFS_VERSION)
2N/A return (NULL);
2N/A
2N/A fs = umem_cache_alloc(libuvfs_fs_cache, UMEM_NOFAIL);
2N/A
2N/A fs->fs_dev = -1;
2N/A fs->fs_fsid = fsid;
2N/A
2N/A fs->fs_io_maxread = 0;
2N/A fs->fs_io_maxwrite = 0;
2N/A fs->fs_max_dthreads = 0;
2N/A fs->fs_cur_dthreads = 0;
2N/A
2N/A libuvfs_init_callbacks(fs);
2N/A
2N/A fs->fs_door = -1;
2N/A
2N/A fs->fs_scf_handle = NULL;
2N/A fs->fs_scf_error = 0;
2N/A fs->fs_scf_props = NULL;
2N/A fs->fs_daemon_fmri_size = 0;
2N/A fs->fs_daemon_fmri = NULL;
2N/A
2N/A if (fs->fs_fsid == LIBUVFS_FSID_SVC)
2N/A libuvfs_get_daemon_fsid(fs);
2N/A
2N/A libuvfs_fs_rand(fs);
2N/A fs->fs_fid_seq = 1;
2N/A
2N/A return (fs);
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_destroy_fs(libuvfs_fs_t *fs)
2N/A{
2N/A if (fs->fs_dev >= 0)
2N/A (void) close(fs->fs_dev);
2N/A if (fs->fs_door >= 0)
2N/A (void) close(fs->fs_door);
2N/A
2N/A if (fs->fs_scf_props != NULL)
2N/A scf_simple_app_props_free(fs->fs_scf_props);
2N/A if (fs->fs_scf_handle != NULL)
2N/A scf_handle_destroy(fs->fs_scf_handle);
2N/A if (fs->fs_daemon_fmri != NULL)
2N/A umem_free(fs->fs_daemon_fmri, fs->fs_daemon_fmri_size);
2N/A
2N/A umem_cache_free(libuvfs_fs_cache, fs);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic int
2N/Alibuvfs_fs_construct(void *vfs, void *foo, int bar)
2N/A{
2N/A libuvfs_fs_t *fs = vfs;
2N/A
2N/A (void) mutex_init(&fs->fs_lock, USYNC_THREAD, NULL);
2N/A (void) mutex_init(&fs->fs_stash_lock, USYNC_THREAD, NULL);
2N/A (void) mutex_init(&fs->fs_name_lock, USYNC_THREAD, NULL);
2N/A (void) cond_init(&fs->fs_daemon_cv, USYNC_THREAD, NULL);
2N/A (void) pthread_attr_init(&fs->fs_pthread_attr);
2N/A libuvfs_stash_fs_construct(fs);
2N/A libuvfs_name_fs_construct(fs);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Astatic void
2N/Alibuvfs_fs_destroy(void *vfs, void *foo)
2N/A{
2N/A libuvfs_fs_t *fs = vfs;
2N/A
2N/A libuvfs_name_fs_destroy(fs);
2N/A libuvfs_stash_fs_destroy(fs);
2N/A (void) pthread_attr_destroy(&fs->fs_pthread_attr);
2N/A (void) cond_destroy(&fs->fs_daemon_cv);
2N/A (void) mutex_destroy(&fs->fs_stash_lock);
2N/A (void) mutex_destroy(&fs->fs_lock);
2N/A}
2N/A
2N/Astatic int
2N/Alibuvfs_umem_alloc_fail(void)
2N/A{
2N/A if (atomic_inc_32_nv(&libuvfs_umem_alloc_failures) >
2N/A libuvfs_umem_alloc_max_failures)
2N/A return (UMEM_CALLBACK_EXIT(255));
2N/A
2N/A (void) sleep(libuvfs_umem_alloc_failure_sleep);
2N/A
2N/A return (UMEM_CALLBACK_RETRY);
2N/A}
2N/A
2N/Achar *
2N/Alibuvfs_strdup(const char *str)
2N/A{
2N/A char *rc;
2N/A
2N/A rc = umem_alloc(strlen(str) + 1, UMEM_NOFAIL);
2N/A
2N/A return (strcpy(rc, str));
2N/A}
2N/A
2N/Avoid
2N/Alibuvfs_strfree(char *str)
2N/A{
2N/A umem_free(str, strlen(str) + 1);
2N/A}
2N/A
2N/Achar *
2N/Alibuvfs_hexdump(const void *stuff, int howlong)
2N/A{
2N/A static char *hex = "0123456789abcdef";
2N/A char *rc = umem_alloc(howlong * 2 + 1, UMEM_NOFAIL);
2N/A uint8_t *bytes = (uint8_t *)stuff;
2N/A int i;
2N/A
2N/A rc[howlong * 2] = '\0';
2N/A
2N/A for (i = 0; i < howlong; i++) {
2N/A rc[2*i] = hex[bytes[i] >> 4];
2N/A rc[2*i+1] = hex[bytes[i] & 0x0f];
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A#ifndef NBITSMINOR64
2N/A#define NBITSMINOR64 32
2N/A#endif
2N/A#ifndef MAXMAJ64
2N/A#define MAXMAJ64 0xffffffffUL
2N/A#endif
2N/A#ifndef MAXMIN64
2N/A#define MAXMIN64 0xffffffffUL
2N/A#endif
2N/A
2N/Auint64_t
2N/Alibuvfs_expldev(dev_t dev)
2N/A{
2N/A#ifndef _LP64
2N/A major_t major = (major_t)dev >> NBITSMINOR32 & MAXMAJ32;
2N/A return (((uint64_t)major << NBITSMINOR64) |
2N/A ((minor_t)dev & MAXMIN32));
2N/A#else
2N/A return (dev);
2N/A#endif
2N/A}
2N/A
2N/Adev_t
2N/Alibuvfs_cmpldev(uint64_t dev)
2N/A{
2N/A#ifndef _LP64
2N/A minor_t minor = (minor_t)dev & MAXMIN64;
2N/A major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64;
2N/A
2N/A if (major > MAXMAJ32 || minor > MAXMIN32)
2N/A return ((dev_t)-1);
2N/A
2N/A return (((dev32_t)major << NBITSMINOR32) | minor);
2N/A#else
2N/A return (dev);
2N/A#endif
2N/A}
2N/A
2N/A#pragma init(libuvfs_fs_init)
2N/Astatic void
2N/Alibuvfs_fs_init(void)
2N/A{
2N/A umem_nofail_callback(libuvfs_umem_alloc_fail);
2N/A libuvfs_fs_cache = umem_cache_create("libuvfs_fs_cache",
2N/A sizeof (libuvfs_fs_t), 0, libuvfs_fs_construct, libuvfs_fs_destroy,
2N/A NULL, NULL, NULL, 0);
2N/A
2N/A srand(getpid() + time(0));
2N/A}
2N/A
2N/A#pragma fini(libuvfs_fs_fini)
2N/Astatic void
2N/Alibuvfs_fs_fini(void)
2N/A{
2N/A umem_cache_destroy(libuvfs_fs_cache);
2N/A}