sdev_zvolops.c revision d65686849024838243515b5c40ae2c479460b4b5
/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2013 Joyent, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <sys/zfs_ioctl.h>
#include <sys/vfs_opreg.h>
struct vnodeops *devzvol_vnodeops;
static uint64_t devzvol_gen = 0;
static uint64_t devzvol_zclist;
static size_t devzvol_zclist_size;
static ldi_ident_t devzvol_li;
static ldi_handle_t devzvol_lh;
static kmutex_t devzvol_mtx;
static boolean_t devzvol_isopen;
static major_t devzvol_major;
/*
* ready to go
*/
int (*szcm)(char *);
int
sdev_zvol_create_minor(char *dsname)
{
return (-1);
}
int
{
return (-1);
}
int
{
int rc;
&devzvol_lh, devzvol_li))
return (-1);
return (rc);
}
if ((szcm = (int (*)(char *))
return (rc);
}
return (rc);
}
return (-1);
return (0);
}
void
{
(void) ddi_modclose(zfs_mod);
}
}
int
{
int size = 8000;
int unused;
int rc;
if (cmd != ZFS_IOC_POOL_CONFIGS)
if (!devzvol_isopen) {
if ((rc = devzvol_open_zfs()) == 0) {
} else {
if (cmd != ZFS_IOC_POOL_CONFIGS)
return (ENXIO);
}
}
KM_SLEEP);
&unused);
int newsize;
goto again;
}
if (alloc_size == NULL)
else
*alloc_size = size;
if (cmd != ZFS_IOC_POOL_CONFIGS)
return (rc);
}
/* figures out if the objset exists and returns its type */
int
{
int rc;
sdcmn_err13(("found cached minor node"));
if (type)
*type = DMU_OST_ZVOL;
return (0);
}
return (rc);
}
/*
* path and an optional name; otherwise NULL
*/
char *
{
char *dsname;
const char *ptr;
int dslen;
return (NULL);
return (NULL);
else
return (NULL);
if (*ptr == '/')
ptr++;
if (dslen)
dslen++; /* plus null */
if (name)
if (*ptr) {
if (name)
}
if (name)
return (dsname);
}
/*
* check if the zvol's sdev_node is still valid, which means make
* sure the zvol is still valid. zvol minors aren't proactively
* destroyed when the zvol is destroyed, so we use a validator to clean
* these up (in other words, when such nodes are encountered during
* subsequent lookup() and readdir() operations) so that only valid
* nodes are returned. The ordering between devname_lookup_func and
* devzvol_validate is a little inefficient in the case of invalid
* or stale nodes because devname_lookup_func calls
* devzvol_create_{dir, link}, then the validator says it's invalid,
* and then the node gets cleaned up.
*/
int
{
char *dsname;
int rc;
/*
* validate only READY nodes; if someone is sitting on the
* directory of a dataset that just got destroyed we could
* get a zombie node which we just skip.
*/
return (SDEV_VTOR_SKIP);
}
return (SDEV_VTOR_VALID);
return (SDEV_VTOR_INVALID);
if (rc != 0) {
return (SDEV_VTOR_INVALID);
}
sdcmn_err13((" v_type %d do_type %d",
do_type != DMU_OST_ZVOL) ||
return (SDEV_VTOR_STALE);
}
long val = 0;
return (SDEV_VTOR_STALE);
}
}
return (SDEV_VTOR_VALID);
}
/*
* creates directories as needed in response to a readdir
*/
void
{
int pools = 0;
int rc;
sdcmn_err13(("devzvol_create_pool_dirs"));
switch (rc) {
case 0:
/* new generation */
if (devzvol_zclist)
break;
case EEXIST:
/*
* no change in the configuration; still need
* to do lookups in case we did a lookup in
*/
size);
break;
default:
size);
goto out;
}
devzvol_zclist_size, &nv, 0);
if (rc) {
devzvol_gen = 0;
devzvol_zclist_size = 0;
goto out;
}
/* should either work, or not be visible from a zone */
if (rc == 0)
pools++;
}
if (devzvol_isopen && pools == 0) {
/* clean up so zfs can be unloaded */
}
out:
}
/*ARGSUSED3*/
static int
{
gethrestime(&now);
return (0);
}
/*ARGSUSED3*/
static int
{
int rc;
char *dsname;
char *x;
char str[MAXNAMELEN];
return (-1);
}
/*
* This is a valid zvol; create a symlink that points to the
*/
*pathname = '\0';
strlen(ZVOL_FULL_RDEV_DIR)) == 0)
return (0);
}
/* Clean zvol sdev_nodes that are no longer valid. */
static void
{
}
while (dv) {
switch (devzvol_validate(dv)) {
case SDEV_VTOR_VALID:
case SDEV_VTOR_SKIP:
continue;
case SDEV_VTOR_INVALID:
sdcmn_err7(("prunedir: destroy invalid "
break;
}
continue;
}
/* remove the cache node */
}
}
/*
* This function is used to create a dir or dev inside a zone's /dev when the
* zone has a zvol that is dynamically created within the zone (i.e. inside
* of a delegated dataset. Since there is no /devices tree within a zone,
* making symlinks.
*/
static int
{
int res;
char *dsname;
gethrestime(&now);
return (ENOENT);
return (ENOENT);
}
if (do_type == DMU_OST_ZVOL)
if (expected_type == VDIR) {
} else {
int rc;
return (ENOENT);
}
else
}
if (res != 0)
return (ENOENT);
return (0);
}
/*ARGSUSED*/
static int
{
char *dsname;
int error;
/* execute access is required to search the directory */
return (error);
if (SDEV_IS_GLOBAL(parent)) {
/*
* During iter_datasets, don't create GZ dev when running in
* NGZ. We can't return ENOENT here since that could
* incorrectly trigger the creation of the dev from the
* recursive call through prof_filldir during iter_datasets.
*/
if (getzoneid() != GLOBAL_ZONEID) {
return (EPERM);
}
} else {
int res;
/*
* If we're in the global zone and reach down into a non-global
* of all of the zvol devices for every zone into the non-global
* zone's /dev tree. This could be a big security hole. To
* prevent this, disallow the global zone from looking inside
* delegated datasets, which cannot be used by the global zone.
*/
if (getzoneid() == GLOBAL_ZONEID)
return (EPERM);
/*
* We won't find a zvol that was dynamically created inside
* a NGZ, within a delegated dataset, in the zone's dev profile
* but prof_lookup will also find it via sdev_cache_lookup.
*/
/*
* We have to create the sdev node for the dymamically
* created zvol.
*/
return (ENOENT);
}
return (res);
}
if (dsname) {
if (error != 0) {
goto out;
}
if (do_type == DMU_OST_ZVOL)
}
/*
* the callbacks expect:
*
* parent->sdev_path nm
*
* sdev_name is always last path component of sdev_path
*/
if (expected_type == VDIR) {
} else {
}
out:
if (dsname)
return (error);
}
/*
* We allow create to find existing nodes
* - if the node doesn't exist - EROFS
* - creating an existing dir read-only succeeds, otherwise EISDIR
* - exclusive creates fail - EEXIST
*/
/*ARGSUSED2*/
static int
{
int error;
NULL);
if (error == 0) {
else
if (error) {
} else
}
return (error);
}
void
{
int rc;
char *ptr;
goto skip;
if (rc == 0) {
goto skip;
} else {
/*
* EBUSY == problem with zvols's dmu holds?
* EPERM when in a NGZ and traversing up and out.
*/
goto skip;
}
if (arg == ZFS_IOC_DATASET_LIST_NEXT &&
skip:
}
}
void
{
}
/*ARGSUSED4*/
static int
{
char *ptr;
}
if (uiop->uio_offset == 0)
}
return (ENOENT);
ptr++;
}
const fs_operation_def_t devzvol_vnodeops_tbl[] = {
};