FreeBSD: Simplify zvol and fix locking

zvol_geom_bio_strategy should handle its own use of the zvol
suspend reader lock and ensure the zilog exists when needed.

A few other places using the zvol zilog should use the suspend
reader lock as well.

Simplify consumers of zvol_geom_bio_strategy, fix the locking, and
while in here, use the boolean_t constants with doread.

Reviewed-by: Matt Macy <mmacy@FreeBSD.org>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes #10381
This commit is contained in:
Ryan Moeller 2020-06-03 13:45:12 -04:00 committed by GitHub
parent a9dcfac51c
commit c0eb5c35ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 25 additions and 66 deletions

View File

@ -199,7 +199,6 @@ static int zvol_geom_access(struct g_provider *pp, int acr, int acw, int ace);
static void zvol_geom_worker(void *arg); static void zvol_geom_worker(void *arg);
static void zvol_geom_bio_start(struct bio *bp); static void zvol_geom_bio_start(struct bio *bp);
static int zvol_geom_bio_getattr(struct bio *bp); static int zvol_geom_bio_getattr(struct bio *bp);
static void zvol_geom_bio_check_zilog(struct bio *bp);
/* static d_strategy_t zvol_geom_bio_strategy; (declared elsewhere) */ /* static d_strategy_t zvol_geom_bio_strategy; (declared elsewhere) */
/* /*
@ -487,23 +486,7 @@ zvol_geom_worker(void *arg)
continue; continue;
} }
mtx_unlock(&zsg->zsg_queue_mtx); mtx_unlock(&zsg->zsg_queue_mtx);
rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER);
zvol_geom_bio_check_zilog(bp);
switch (bp->bio_cmd) {
case BIO_FLUSH:
zil_commit(zv->zv_zilog, ZVOL_OBJ);
g_io_deliver(bp, 0);
break;
case BIO_READ:
case BIO_WRITE:
case BIO_DELETE:
zvol_geom_bio_strategy(bp); zvol_geom_bio_strategy(bp);
break;
default:
g_io_deliver(bp, EOPNOTSUPP);
break;
}
rw_exit(&zv->zv_suspend_lock);
} }
} }
@ -529,24 +512,8 @@ zvol_geom_bio_start(struct bio *bp)
wakeup_one(&zsg->zsg_queue); wakeup_one(&zsg->zsg_queue);
return; return;
} }
rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER);
zvol_geom_bio_check_zilog(bp);
switch (bp->bio_cmd) {
case BIO_FLUSH:
zil_commit(zv->zv_zilog, ZVOL_OBJ);
g_io_deliver(bp, 0);
break;
case BIO_READ:
case BIO_WRITE:
case BIO_DELETE:
zvol_geom_bio_strategy(bp); zvol_geom_bio_strategy(bp);
break;
default:
g_io_deliver(bp, EOPNOTSUPP);
break;
}
rw_exit(&zv->zv_suspend_lock);
} }
static int static int
@ -586,24 +553,6 @@ zvol_geom_bio_getattr(struct bio *bp)
return (1); return (1);
} }
static void
zvol_geom_bio_check_zilog(struct bio *bp)
{
zvol_state_t *zv;
zv = bp->bio_to->private;
ASSERT(zv != NULL);
switch (bp->bio_cmd) {
case BIO_FLUSH:
case BIO_WRITE:
case BIO_DELETE:
zvol_ensure_zilog(zv);
default:
break;
}
}
static void static void
zvol_geom_bio_strategy(struct bio *bp) zvol_geom_bio_strategy(struct bio *bp)
{ {
@ -614,7 +563,7 @@ zvol_geom_bio_strategy(struct bio *bp)
objset_t *os; objset_t *os;
zfs_locked_range_t *lr; zfs_locked_range_t *lr;
int error = 0; int error = 0;
boolean_t doread = 0; boolean_t doread = B_FALSE;
boolean_t is_dumpified; boolean_t is_dumpified;
boolean_t sync; boolean_t sync;
@ -628,22 +577,26 @@ zvol_geom_bio_strategy(struct bio *bp)
goto out; goto out;
} }
if (bp->bio_cmd != BIO_READ && (zv->zv_flags & ZVOL_RDONLY)) { rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER);
error = SET_ERROR(EROFS);
goto out;
}
switch (bp->bio_cmd) { switch (bp->bio_cmd) {
case BIO_FLUSH:
goto sync;
case BIO_READ: case BIO_READ:
doread = 1; doread = B_TRUE;
break;
case BIO_WRITE: case BIO_WRITE:
case BIO_FLUSH:
case BIO_DELETE: case BIO_DELETE:
if (zv->zv_flags & ZVOL_RDONLY) {
error = SET_ERROR(EROFS);
goto resume;
}
zvol_ensure_zilog(zv);
if (bp->bio_cmd == BIO_FLUSH)
goto sync;
break; break;
default: default:
error = EOPNOTSUPP; error = EOPNOTSUPP;
goto out; goto resume;
} }
off = bp->bio_offset; off = bp->bio_offset;
@ -657,7 +610,7 @@ zvol_geom_bio_strategy(struct bio *bp)
if (resid > 0 && (off < 0 || off >= volsize)) { if (resid > 0 && (off < 0 || off >= volsize)) {
error = SET_ERROR(EIO); error = SET_ERROR(EIO);
goto out; goto resume;
} }
is_dumpified = B_FALSE; is_dumpified = B_FALSE;
@ -723,6 +676,8 @@ unlock:
sync: sync:
zil_commit(zv->zv_zilog, ZVOL_OBJ); zil_commit(zv->zv_zilog, ZVOL_OBJ);
} }
resume:
rw_exit(&zv->zv_suspend_lock);
out: out:
if (bp->bio_to) if (bp->bio_to)
g_io_deliver(bp, error); g_io_deliver(bp, error);
@ -797,7 +752,6 @@ zvol_cdev_write(struct cdev *dev, struct uio *uio, int ioflag)
rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER); rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER);
zvol_ensure_zilog(zv); zvol_ensure_zilog(zv);
rw_exit(&zv->zv_suspend_lock);
lr = zfs_rangelock_enter(&zv->zv_rangelock, uio->uio_loffset, lr = zfs_rangelock_enter(&zv->zv_rangelock, uio->uio_loffset,
uio->uio_resid, RL_WRITER); uio->uio_resid, RL_WRITER);
@ -826,6 +780,7 @@ zvol_cdev_write(struct cdev *dev, struct uio *uio, int ioflag)
zfs_rangelock_exit(lr); zfs_rangelock_exit(lr);
if (sync) if (sync)
zil_commit(zv->zv_zilog, ZVOL_OBJ); zil_commit(zv->zv_zilog, ZVOL_OBJ);
rw_exit(&zv->zv_suspend_lock);
return (error); return (error);
} }
@ -1015,8 +970,10 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data,
*(off_t *)data = zv->zv_volsize; *(off_t *)data = zv->zv_volsize;
break; break;
case DIOCGFLUSH: case DIOCGFLUSH:
rw_enter(&zv->zv_suspend_lock, ZVOL_RW_READER);
if (zv->zv_zilog != NULL) if (zv->zv_zilog != NULL)
zil_commit(zv->zv_zilog, ZVOL_OBJ); zil_commit(zv->zv_zilog, ZVOL_OBJ);
rw_exit(&zv->zv_suspend_lock);
break; break;
case DIOCGDELETE: case DIOCGDELETE:
if (!zvol_unmap_enabled) if (!zvol_unmap_enabled)
@ -1121,8 +1078,10 @@ zvol_ensure_zilog(zvol_state_t *zv)
* additional lock in this path. * additional lock in this path.
*/ */
if (zv->zv_zilog == NULL) { if (zv->zv_zilog == NULL) {
if (!rw_tryupgrade(&zv->zv_suspend_lock)) {
rw_exit(&zv->zv_suspend_lock); rw_exit(&zv->zv_suspend_lock);
rw_enter(&zv->zv_suspend_lock, RW_WRITER); rw_enter(&zv->zv_suspend_lock, RW_WRITER);
}
if (zv->zv_zilog == NULL) { if (zv->zv_zilog == NULL) {
zv->zv_zilog = zil_open(zv->zv_objset, zv->zv_zilog = zil_open(zv->zv_objset,
zvol_get_data); zvol_get_data);