sdev_zvolops.c revision ff060bd829a533f5a355dbc1e21cf7652ce8f61b
/*
* 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.
*/
#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;
/*
* ready to go
*/
int (*szcm)(char *);
int
sdev_zvol_create_minor(char *dsname)
{
}
int
{
}
int
{
int rc;
&devzvol_lh, devzvol_li))
return (-1);
return (rc);
}
if ((szcm = (int (*)(char *))
return (rc);
}
return (rc);
}
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",
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) {
/* skip stale nodes */
sdcmn_err13((" stale"));
continue;
}
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 */
SDEV_CACHE_DELETE) == 0)
else
}
}
/*ARGSUSED*/
static int
{
char *dsname;
int error;
/* execute access is required to search the directory */
return (error);
if (!SDEV_IS_GLOBAL(parent)) {
}
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? */
ASSERT(0);
goto skip;
}
if (arg == ZFS_IOC_DATASET_LIST_NEXT &&
skip:
}
}
void
{
}
/*ARGSUSED4*/
static int
{
char *ptr;
}
if (uiop->uio_offset == 0)
}
}
const fs_operation_def_t devzvol_vnodeops_tbl[] = {
};