summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.834
-rw-r--r--sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c12
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c468
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h7
4 files changed, 403 insertions, 118 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
index 8fac48a..d14ce13 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
@@ -30,7 +30,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 20, 2014
+.Dd April 5, 2014
.Dt ZFS 8
.Os
.Sh NAME
@@ -1306,6 +1306,38 @@ Consequently, writes to a sparse volume can fail with
when the pool is low on space. For a sparse volume, changes to
.Sy volsize
are not reflected in the reservation.
+.It Sy volmode Ns = Ns Cm default | geom | dev | none
+This property specifies how volumes should be exposed to the OS.
+Setting it to
+.Sy geom
+exposes volumes as
+.Xr geom 4
+providers, providing maximal functionality.
+Setting it to
+.Sy dev
+exposes volumes only as cdev device in devfs.
+Such volumes can be accessed only as raw disk device files, i.e. they
+can not be partitioned, mounted, participate in RAIDs, etc, but they
+are faster, and in some use scenarios with untrusted consumer, such as
+NAS or VM storage, can be more safe.
+Volumes with property set to
+.Sy none
+are not exposed outside ZFS, but can be snapshoted, cloned, replicated, etc,
+that can be suitable for backup purposes.
+Value
+.Sy default
+means that volumes exposition is controlled by system-wide sysctl/tunable
+.Va vfs.zfs.vol.mode ,
+where
+.Sy geom ,
+.Sy dev
+and
+.Sy none
+are encoded as 1, 2 and 3 respectively.
+The default values is
+.Sy geom .
+This property can be changed any time, but so far it is processed only
+during volume creation and pool import.
.It Sy vscan Ns = Ns Cm off | on
The
.Sy vscan
diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c b/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
index 8403732..fde51a7 100644
--- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
+++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c
@@ -198,6 +198,14 @@ zfs_prop_init(void)
{ NULL }
};
+ static zprop_index_t volmode_table[] = {
+ { "default", ZFS_VOLMODE_DEFAULT },
+ { "geom", ZFS_VOLMODE_GEOM },
+ { "dev", ZFS_VOLMODE_DEV },
+ { "none", ZFS_VOLMODE_NONE },
+ { NULL }
+ };
+
/* inherit index properties */
zprop_register_index(ZFS_PROP_SYNC, "sync", ZFS_SYNC_STANDARD,
PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
@@ -242,6 +250,10 @@ zfs_prop_init(void)
zprop_register_index(ZFS_PROP_LOGBIAS, "logbias", ZFS_LOGBIAS_LATENCY,
PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"latency | throughput", "LOGBIAS", logbias_table);
+ zprop_register_index(ZFS_PROP_VOLMODE, "volmode",
+ ZFS_VOLMODE_DEFAULT, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT | ZFS_TYPE_VOLUME,
+ "default | geom | dev | none", "VOLMODE", volmode_table);
/* inherit index (boolean) properties */
zprop_register_index(ZFS_PROP_ATIME, "atime", 1, PROP_INHERIT,
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
index 5d14597..fb3789f 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -66,6 +66,7 @@
#include <sys/spa.h>
#include <sys/spa_impl.h>
#include <sys/zio.h>
+#include <sys/disk.h>
#include <sys/dmu_traverse.h>
#include <sys/dnode.h>
#include <sys/dsl_dataset.h>
@@ -75,6 +76,7 @@
#include <sys/sunddi.h>
#include <sys/dirent.h>
#include <sys/policy.h>
+#include <sys/queue.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
#include <sys/zil.h>
@@ -114,6 +116,13 @@ static char *zvol_tag = "zvol_tag";
*/
static uint32_t zvol_minors;
+SYSCTL_DECL(_vfs_zfs);
+SYSCTL_NODE(_vfs_zfs, OID_AUTO, vol, CTLFLAG_RW, 0, "ZFS VOLUME");
+static int volmode = ZFS_VOLMODE_GEOM;
+TUNABLE_INT("vfs.zfs.vol.mode", &volmode);
+SYSCTL_INT(_vfs_zfs_vol, OID_AUTO, mode, CTLFLAG_RWTUN, &volmode, 0,
+ "Expose as GEOM providers (1), device files (2) or neither");
+
typedef struct zvol_extent {
list_node_t ze_node;
dva_t ze_dva; /* dva associated with this extent */
@@ -124,9 +133,11 @@ typedef struct zvol_extent {
* The in-core state of each volume.
*/
typedef struct zvol_state {
+ LIST_ENTRY(zvol_state) zv_links;
char zv_name[MAXPATHLEN]; /* pool/dd name */
uint64_t zv_volsize; /* amount of space we advertise */
uint64_t zv_volblocksize; /* volume block size */
+ struct cdev *zv_dev; /* non-GEOM device */
struct g_provider *zv_provider; /* GEOM provider */
uint8_t zv_min_bs; /* minimum addressable block shift */
uint8_t zv_flags; /* readonly, dumpified, etc. */
@@ -137,10 +148,13 @@ typedef struct zvol_state {
znode_t zv_znode; /* for range locking */
dmu_buf_t *zv_dbuf; /* bonus handle */
int zv_state;
+ int zv_volmode; /* Provide GEOM or cdev */
struct bio_queue_head zv_queue;
struct mtx zv_queue_mtx; /* zv_queue mutex */
} zvol_state_t;
+static LIST_HEAD(, zvol_state) all_zvols;
+
/*
* zvol specific flags
*/
@@ -154,6 +168,25 @@ typedef struct zvol_state {
*/
int zvol_maxphys = DMU_MAX_ACCESS/2;
+static d_open_t zvol_d_open;
+static d_close_t zvol_d_close;
+static d_read_t zvol_read;
+static d_write_t zvol_write;
+static d_ioctl_t zvol_d_ioctl;
+static d_strategy_t zvol_strategy;
+
+static struct cdevsw zvol_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = zvol_d_open,
+ .d_close = zvol_d_close,
+ .d_read = zvol_read,
+ .d_write = zvol_write,
+ .d_ioctl = zvol_d_ioctl,
+ .d_strategy = zvol_strategy,
+ .d_name = "zvol",
+ .d_flags = D_DISK | D_TRACKCLOSE,
+};
+
extern int zfs_set_prop_nvlist(const char *, zprop_source_t,
nvlist_t *, nvlist_t *);
static void zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off,
@@ -164,7 +197,6 @@ static int zvol_dumpify(zvol_state_t *zv);
static int zvol_dump_fini(zvol_state_t *zv);
static int zvol_dump_init(zvol_state_t *zv, boolean_t resize);
-static zvol_state_t *zvol_geom_create(const char *name);
static void zvol_geom_run(zvol_state_t *zv);
static void zvol_geom_destroy(zvol_state_t *zv);
static int zvol_geom_access(struct g_provider *pp, int acr, int acw, int ace);
@@ -186,14 +218,16 @@ zvol_size_changed(zvol_state_t *zv)
spec_size_invalidate(dev, VBLK);
spec_size_invalidate(dev, VCHR);
#else /* !sun */
- struct g_provider *pp;
+ if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
+ struct g_provider *pp;
- pp = zv->zv_provider;
- if (pp == NULL)
- return;
- g_topology_lock();
- g_resize_provider(pp, zv->zv_volsize);
- g_topology_unlock();
+ pp = zv->zv_provider;
+ if (pp == NULL)
+ return;
+ g_topology_lock();
+ g_resize_provider(pp, zv->zv_volsize);
+ g_topology_unlock();
+ }
#endif /* !sun */
}
@@ -250,26 +284,16 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
static zvol_state_t *
zvol_minor_lookup(const char *name)
{
- struct g_provider *pp;
- struct g_geom *gp;
- zvol_state_t *zv = NULL;
+ zvol_state_t *zv;
ASSERT(MUTEX_HELD(&spa_namespace_lock));
- g_topology_lock();
- LIST_FOREACH(gp, &zfs_zvol_class.geom, geom) {
- pp = LIST_FIRST(&gp->provider);
- if (pp == NULL)
- continue;
- zv = pp->private;
- if (zv == NULL)
- continue;
+ LIST_FOREACH(zv, &all_zvols, zv_links) {
if (strcmp(zv->zv_name, name) == 0)
break;
}
- g_topology_unlock();
- return (gp != NULL ? zv : NULL);
+ return (zv);
}
/* extent mapping arg */
@@ -507,8 +531,11 @@ zvol_create_minor(const char *name)
zfs_soft_state_t *zs;
zvol_state_t *zv;
objset_t *os;
+ struct cdev *dev;
+ struct g_provider *pp;
+ struct g_geom *gp;
dmu_object_info_t doi;
- uint64_t volsize;
+ uint64_t volsize, mode;
int error;
ZFS_LOG(1, "Creating ZVOL %s...", name);
@@ -569,20 +596,51 @@ zvol_create_minor(const char *name)
zv = zs->zss_data = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP);
#else /* !sun */
+ zv = kmem_zalloc(sizeof(*zv), KM_SLEEP);
+ zv->zv_state = 0;
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
if (error) {
- ASSERT(error == 0);
+ kmem_free(zv, sizeof(*zv));
dmu_objset_disown(os, zvol_tag);
mutex_exit(&spa_namespace_lock);
return (error);
}
+ error = dsl_prop_get_integer(name,
+ zfs_prop_to_name(ZFS_PROP_VOLMODE), &mode, NULL);
+ if (error != 0 || mode == ZFS_VOLMODE_DEFAULT)
+ mode = volmode;
DROP_GIANT();
- g_topology_lock();
- zv = zvol_geom_create(name);
zv->zv_volsize = volsize;
- zv->zv_provider->mediasize = zv->zv_volsize;
-
+ zv->zv_volmode = mode;
+ if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
+ g_topology_lock();
+ gp = g_new_geomf(&zfs_zvol_class, "zfs::zvol::%s", name);
+ gp->start = zvol_geom_start;
+ gp->access = zvol_geom_access;
+ pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, name);
+ pp->flags |= G_PF_DIRECT_RECEIVE | G_PF_DIRECT_SEND;
+ pp->sectorsize = DEV_BSIZE;
+ pp->mediasize = zv->zv_volsize;
+ pp->private = zv;
+
+ zv->zv_provider = pp;
+ bioq_init(&zv->zv_queue);
+ mtx_init(&zv->zv_queue_mtx, "zvol", NULL, MTX_DEF);
+ } else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
+ if (make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
+ &dev, &zvol_cdevsw, NULL, UID_ROOT, GID_OPERATOR,
+ 0640, "%s/%s", ZVOL_DRIVER, name) != 0) {
+ kmem_free(zv, sizeof(*zv));
+ dmu_objset_disown(os, FTAG);
+ mutex_exit(&spa_namespace_lock);
+ return (SET_ERROR(ENXIO));
+ }
+ zv->zv_dev = dev;
+ dev->si_iosize_max = MAXPHYS;
+ dev->si_drv2 = zv;
+ }
+ LIST_INSERT_HEAD(&all_zvols, zv, zv_links);
#endif /* !sun */
(void) strlcpy(zv->zv_name, name, MAXPATHLEN);
@@ -613,10 +671,13 @@ zvol_create_minor(const char *name)
mutex_exit(&spa_namespace_lock);
- zvol_geom_run(zv);
-
- g_topology_unlock();
+#ifndef sun
+ if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
+ zvol_geom_run(zv);
+ g_topology_unlock();
+ }
PICKUP_GIANT();
+#endif
ZFS_LOG(1, "ZVOL %s created.", name);
@@ -642,12 +703,20 @@ zvol_remove_zv(zvol_state_t *zv)
#ifdef sun
(void) snprintf(nmbuf, sizeof (nmbuf), "%u,raw", minor);
ddi_remove_minor_node(zfs_dip, nmbuf);
+#else
+ LIST_REMOVE(zv, zv_links);
+ if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
+ g_topology_lock();
+ zvol_geom_destroy(zv);
+ g_topology_unlock();
+ } else if (zv->zv_volmode == ZFS_VOLMODE_DEV)
+ destroy_dev(zv->zv_dev);
#endif /* sun */
avl_destroy(&zv->zv_znode.z_range_avl);
mutex_destroy(&zv->zv_znode.z_range_lock);
- zvol_geom_destroy(zv);
+ kmem_free(zv, sizeof(*zv));
zvol_minors--;
return (0);
@@ -664,9 +733,7 @@ zvol_remove_minor(const char *name)
mutex_exit(&spa_namespace_lock);
return (SET_ERROR(ENXIO));
}
- g_topology_lock();
rc = zvol_remove_zv(zv);
- g_topology_unlock();
mutex_exit(&spa_namespace_lock);
return (rc);
}
@@ -802,24 +869,15 @@ zvol_update_volsize(objset_t *os, uint64_t volsize)
void
zvol_remove_minors(const char *name)
{
- struct g_geom *gp, *gptmp;
- struct g_provider *pp;
- zvol_state_t *zv;
+ zvol_state_t *zv, *tzv;
size_t namelen;
namelen = strlen(name);
DROP_GIANT();
mutex_enter(&spa_namespace_lock);
- g_topology_lock();
- LIST_FOREACH_SAFE(gp, &zfs_zvol_class.geom, geom, gptmp) {
- pp = LIST_FIRST(&gp->provider);
- if (pp == NULL)
- continue;
- zv = pp->private;
- if (zv == NULL)
- continue;
+ LIST_FOREACH_SAFE(zv, &all_zvols, zv_links, tzv) {
if (strcmp(zv->zv_name, name) == 0 ||
(strncmp(zv->zv_name, name, namelen) == 0 &&
zv->zv_name[namelen] == '/')) {
@@ -827,7 +885,6 @@ zvol_remove_minors(const char *name)
}
}
- g_topology_unlock();
mutex_exit(&spa_namespace_lock);
PICKUP_GIANT();
}
@@ -1286,28 +1343,46 @@ zvol_dumpio(zvol_state_t *zv, void *addr, uint64_t offset, uint64_t size,
}
#endif /* sun */
-int
+void
zvol_strategy(struct bio *bp)
{
- zvol_state_t *zv = bp->bio_to->private;
+ zvol_state_t *zv;
uint64_t off, volsize;
size_t resid;
char *addr;
objset_t *os;
rl_t *rl;
int error = 0;
- boolean_t doread = (bp->bio_cmd == BIO_READ);
+ boolean_t doread = 0;
boolean_t is_dumpified;
boolean_t sync;
+ if (bp->bio_to)
+ zv = bp->bio_to->private;
+ else
+ zv = bp->bio_dev->si_drv2;
+
if (zv == NULL) {
- g_io_deliver(bp, ENXIO);
- return (0);
+ error = ENXIO;
+ goto out;
}
if (bp->bio_cmd != BIO_READ && (zv->zv_flags & ZVOL_RDONLY)) {
- g_io_deliver(bp, EROFS);
- return (0);
+ error = EROFS;
+ goto out;
+ }
+
+ switch (bp->bio_cmd) {
+ case BIO_FLUSH:
+ goto sync;
+ case BIO_READ:
+ doread = 1;
+ case BIO_WRITE:
+ case BIO_DELETE:
+ break;
+ default:
+ error = EOPNOTSUPP;
+ goto out;
}
off = bp->bio_offset;
@@ -1320,8 +1395,8 @@ zvol_strategy(struct bio *bp)
resid = bp->bio_length;
if (resid > 0 && (off < 0 || off >= volsize)) {
- g_io_deliver(bp, EIO);
- return (0);
+ error = EIO;
+ goto out;
}
#ifdef illumos
@@ -1393,14 +1468,18 @@ unlock:
zfs_range_unlock(rl);
bp->bio_completed = bp->bio_length - resid;
- if (bp->bio_completed < bp->bio_length)
- bp->bio_error = (off > volsize ? EINVAL : error);
+ if (bp->bio_completed < bp->bio_length && off > volsize)
+ error = EINVAL;
- if (sync)
+ if (sync) {
+sync:
zil_commit(zv->zv_zilog, ZVOL_OBJ);
- g_io_deliver(bp, 0);
-
- return (0);
+ }
+out:
+ if (bp->bio_to)
+ g_io_deliver(bp, error);
+ else
+ biofinish(bp, NULL, error);
}
#ifdef sun
@@ -1459,25 +1538,36 @@ int
zvol_read(dev_t dev, uio_t *uio, cred_t *cr)
{
minor_t minor = getminor(dev);
+#else
+int
+zvol_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+#endif
zvol_state_t *zv;
uint64_t volsize;
rl_t *rl;
int error = 0;
+#ifdef sun
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
return (SET_ERROR(ENXIO));
+#else
+ zv = dev->si_drv2;
+#endif
volsize = zv->zv_volsize;
if (uio->uio_resid > 0 &&
- (uio->uio_loffset < 0 || uio->uio_loffset >= volsize))
+ (uio->uio_loffset < 0 || uio->uio_loffset > volsize))
return (SET_ERROR(EIO));
+#ifdef illumos
if (zv->zv_flags & ZVOL_DUMPIFIED) {
error = physio(zvol_strategy, NULL, dev, B_READ,
zvol_minphys, uio);
return (error);
}
+#endif
rl = zfs_range_lock(&zv->zv_znode, uio->uio_loffset, uio->uio_resid,
RL_READER);
@@ -1500,31 +1590,43 @@ zvol_read(dev_t dev, uio_t *uio, cred_t *cr)
return (error);
}
+#ifdef sun
/*ARGSUSED*/
int
zvol_write(dev_t dev, uio_t *uio, cred_t *cr)
{
minor_t minor = getminor(dev);
+#else
+int
+zvol_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+#endif
zvol_state_t *zv;
uint64_t volsize;
rl_t *rl;
int error = 0;
boolean_t sync;
+#ifdef sun
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
return (SET_ERROR(ENXIO));
+#else
+ zv = dev->si_drv2;
+#endif
volsize = zv->zv_volsize;
if (uio->uio_resid > 0 &&
- (uio->uio_loffset < 0 || uio->uio_loffset >= volsize))
+ (uio->uio_loffset < 0 || uio->uio_loffset > volsize))
return (SET_ERROR(EIO));
+#ifdef illumos
if (zv->zv_flags & ZVOL_DUMPIFIED) {
error = physio(zvol_strategy, NULL, dev, B_WRITE,
zvol_minphys, uio);
return (error);
}
+#endif
sync = !(zv->zv_flags & ZVOL_WCE) ||
(zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS);
@@ -1559,6 +1661,7 @@ zvol_write(dev_t dev, uio_t *uio, cred_t *cr)
return (error);
}
+#ifdef sun
int
zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs)
{
@@ -2232,31 +2335,6 @@ zvol_dump_fini(zvol_state_t *zv)
}
#endif /* sun */
-static zvol_state_t *
-zvol_geom_create(const char *name)
-{
- struct g_provider *pp;
- struct g_geom *gp;
- zvol_state_t *zv;
-
- gp = g_new_geomf(&zfs_zvol_class, "zfs::zvol::%s", name);
- gp->start = zvol_geom_start;
- gp->access = zvol_geom_access;
- pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, name);
- pp->flags |= G_PF_DIRECT_RECEIVE | G_PF_DIRECT_SEND;
- pp->sectorsize = DEV_BSIZE;
-
- zv = kmem_zalloc(sizeof(*zv), KM_SLEEP);
- zv->zv_provider = pp;
- zv->zv_state = 0;
- bioq_init(&zv->zv_queue);
- mtx_init(&zv->zv_queue_mtx, "zvol", NULL, MTX_DEF);
-
- pp->private = zv;
-
- return (zv);
-}
-
static void
zvol_geom_run(zvol_state_t *zv)
{
@@ -2287,8 +2365,6 @@ zvol_geom_destroy(zvol_state_t *zv)
zv->zv_provider = NULL;
pp->private = NULL;
g_wither_geom(pp->geom, ENXIO);
-
- kmem_free(zv, sizeof(*zv));
}
static int
@@ -2537,30 +2613,47 @@ zvol_create_minors(const char *name)
}
static void
-zvol_rename_minor(struct g_geom *gp, const char *newname)
+zvol_rename_minor(zvol_state_t *zv, const char *newname)
{
+ struct g_geom *gp;
struct g_provider *pp;
- zvol_state_t *zv;
+ struct cdev *dev;
ASSERT(MUTEX_HELD(&spa_namespace_lock));
- g_topology_assert();
- pp = LIST_FIRST(&gp->provider);
- ASSERT(pp != NULL);
- zv = pp->private;
- ASSERT(zv != NULL);
+ if (zv->zv_volmode == ZFS_VOLMODE_GEOM) {
+ g_topology_lock();
+ pp = zv->zv_provider;
+ ASSERT(pp != NULL);
+ gp = pp->geom;
+ ASSERT(gp != NULL);
- zv->zv_provider = NULL;
- g_wither_provider(pp, ENXIO);
-
- pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, newname);
- pp->flags |= G_PF_DIRECT_RECEIVE | G_PF_DIRECT_SEND;
- pp->sectorsize = DEV_BSIZE;
- pp->mediasize = zv->zv_volsize;
- pp->private = zv;
- zv->zv_provider = pp;
+ zv->zv_provider = NULL;
+ g_wither_provider(pp, ENXIO);
+
+ pp = g_new_providerf(gp, "%s/%s", ZVOL_DRIVER, newname);
+ pp->flags |= G_PF_DIRECT_RECEIVE | G_PF_DIRECT_SEND;
+ pp->sectorsize = DEV_BSIZE;
+ pp->mediasize = zv->zv_volsize;
+ pp->private = zv;
+ zv->zv_provider = pp;
+ g_error_provider(pp, 0);
+ g_topology_unlock();
+ } else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
+ dev = zv->zv_dev;
+ ASSERT(dev != NULL);
+ zv->zv_dev = NULL;
+ destroy_dev(dev);
+
+ if (make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
+ &dev, &zvol_cdevsw, NULL, UID_ROOT, GID_OPERATOR,
+ 0640, "%s/%s", ZVOL_DRIVER, newname) == 0) {
+ zv->zv_dev = dev;
+ dev->si_iosize_max = MAXPHYS;
+ dev->si_drv2 = zv;
+ }
+ }
strlcpy(zv->zv_name, newname, sizeof(zv->zv_name));
- g_error_provider(pp, 0);
}
void
@@ -2578,28 +2671,169 @@ zvol_rename_minors(const char *oldname, const char *newname)
DROP_GIANT();
mutex_enter(&spa_namespace_lock);
- g_topology_lock();
- LIST_FOREACH(gp, &zfs_zvol_class.geom, geom) {
- pp = LIST_FIRST(&gp->provider);
- if (pp == NULL)
- continue;
- zv = pp->private;
- if (zv == NULL)
- continue;
+ LIST_FOREACH(zv, &all_zvols, zv_links) {
if (strcmp(zv->zv_name, oldname) == 0) {
- zvol_rename_minor(gp, newname);
+ zvol_rename_minor(zv, newname);
} else if (strncmp(zv->zv_name, oldname, oldnamelen) == 0 &&
(zv->zv_name[oldnamelen] == '/' ||
zv->zv_name[oldnamelen] == '@')) {
snprintf(name, sizeof(name), "%s%c%s", newname,
zv->zv_name[oldnamelen],
zv->zv_name + oldnamelen + 1);
- zvol_rename_minor(gp, name);
+ zvol_rename_minor(zv, name);
}
}
- g_topology_unlock();
mutex_exit(&spa_namespace_lock);
PICKUP_GIANT();
}
+
+static int
+zvol_d_open(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+ zvol_state_t *zv;
+ int err = 0;
+
+ mutex_enter(&spa_namespace_lock);
+ zv = dev->si_drv2;
+ if (zv == NULL) {
+ mutex_exit(&spa_namespace_lock);
+ return(ENXIO); /* zvol_create_minor() not done yet */
+ }
+
+ if (zv->zv_total_opens == 0)
+ err = zvol_first_open(zv);
+ if (err) {
+ mutex_exit(&spa_namespace_lock);
+ return (err);
+ }
+ if ((flags & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
+ err = SET_ERROR(EROFS);
+ goto out;
+ }
+ if (zv->zv_flags & ZVOL_EXCL) {
+ err = SET_ERROR(EBUSY);
+ goto out;
+ }
+#ifdef FEXCL
+ if (flags & FEXCL) {
+ if (zv->zv_total_opens != 0) {
+ err = SET_ERROR(EBUSY);
+ goto out;
+ }
+ zv->zv_flags |= ZVOL_EXCL;
+ }
+#endif
+
+ zv->zv_total_opens++;
+ mutex_exit(&spa_namespace_lock);
+ return (err);
+out:
+ if (zv->zv_total_opens == 0)
+ zvol_last_close(zv);
+ mutex_exit(&spa_namespace_lock);
+ return (err);
+}
+
+static int
+zvol_d_close(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+ zvol_state_t *zv;
+ int err = 0;
+
+ mutex_enter(&spa_namespace_lock);
+ zv = dev->si_drv2;
+ if (zv == NULL) {
+ mutex_exit(&spa_namespace_lock);
+ return(ENXIO);
+ }
+
+ if (zv->zv_flags & ZVOL_EXCL) {
+ ASSERT(zv->zv_total_opens == 1);
+ zv->zv_flags &= ~ZVOL_EXCL;
+ }
+
+ /*
+ * If the open count is zero, this is a spurious close.
+ * That indicates a bug in the kernel / DDI framework.
+ */
+ ASSERT(zv->zv_total_opens != 0);
+
+ /*
+ * You may get multiple opens, but only one close.
+ */
+ zv->zv_total_opens--;
+
+ if (zv->zv_total_opens == 0)
+ zvol_last_close(zv);
+
+ mutex_exit(&spa_namespace_lock);
+ return (0);
+}
+
+static int
+zvol_d_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ zvol_state_t *zv;
+ rl_t *rl;
+ off_t offset, length, chunk;
+ int i, error;
+ u_int u;
+
+ zv = dev->si_drv2;
+
+ error = 0;
+ KASSERT(zv->zv_total_opens > 0,
+ ("Device with zero access count in zvol_d_ioctl"));
+
+ i = IOCPARM_LEN(cmd);
+ switch (cmd) {
+ case DIOCGSECTORSIZE:
+ *(u_int *)data = DEV_BSIZE;
+ break;
+ case DIOCGMEDIASIZE:
+ *(off_t *)data = zv->zv_volsize;
+ break;
+ case DIOCGFLUSH:
+ zil_commit(zv->zv_zilog, ZVOL_OBJ);
+ break;
+ case DIOCGDELETE:
+ offset = ((off_t *)data)[0];
+ length = ((off_t *)data)[1];
+ if ((offset % DEV_BSIZE) != 0 || (length % DEV_BSIZE) != 0 ||
+ offset < 0 || offset >= zv->zv_volsize ||
+ length <= 0) {
+ printf("%s: offset=%jd length=%jd\n", __func__, offset,
+ length);
+ error = EINVAL;
+ break;
+ }
+
+ rl = zfs_range_lock(&zv->zv_znode, offset, length, RL_WRITER);
+ dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
+ error = dmu_tx_assign(tx, TXG_WAIT);
+ if (error != 0) {
+ dmu_tx_abort(tx);
+ } else {
+ zvol_log_truncate(zv, tx, offset, length, B_TRUE);
+ dmu_tx_commit(tx);
+ error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ,
+ offset, length);
+ }
+ zfs_range_unlock(rl);
+ if (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)
+ zil_commit(zv->zv_zilog, ZVOL_OBJ);
+ break;
+ case DIOCGSTRIPESIZE:
+ *(off_t *)data = zv->zv_volblocksize;
+ break;
+ case DIOCGSTRIPEOFFSET:
+ *(off_t *)data = 0;
+ break;
+ default:
+ error = ENOIOCTL;
+ }
+
+ return (error);
+}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
index 4745066..e9d7420 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
@@ -145,6 +145,7 @@ typedef enum {
ZFS_PROP_LOGICALUSED,
ZFS_PROP_LOGICALREFERENCED,
ZFS_PROP_INCONSISTENT, /* not exposed to the user */
+ ZFS_PROP_VOLMODE,
ZFS_NUM_PROPS
} zfs_prop_t;
@@ -337,6 +338,12 @@ typedef enum {
ZFS_SYNC_DISABLED = 2
} zfs_sync_type_t;
+typedef enum {
+ ZFS_VOLMODE_DEFAULT = 0,
+ ZFS_VOLMODE_GEOM = 1,
+ ZFS_VOLMODE_DEV = 2,
+ ZFS_VOLMODE_NONE = 3
+} zfs_volmode_t;
/*
* On-disk version number.
OpenPOWER on IntegriCloud