Author: mav
Date: Thu Apr  3 15:04:32 2014
New Revision: 264077
URL: http://svnweb.freebsd.org/changeset/base/264077

Log:
  Add BIO_DELETE support to ZVOL.
  
  It is an adapted merge from the vendor branch of:
      701 UNMAP support for COMSTAR  (in part related to ZFS)
      2130 zvol DKIOCFREE uses nested DMU transactions

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c  Thu Apr  3 
14:58:52 2014        (r264076)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c  Thu Apr  3 
15:04:32 2014        (r264077)
@@ -25,9 +25,12 @@
  * All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ *
+ * Portions Copyright 2010 Robert Milkowski
+ *
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  */
 
-/* Portions Copyright 2010 Robert Milkowski */
 /* Portions Copyright 2011 Martin Matuska <m...@freebsd.org> */
 
 /*
@@ -153,6 +156,8 @@ int zvol_maxphys = DMU_MAX_ACCESS/2;
 
 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,
+    uint64_t len, boolean_t sync);
 static int zvol_remove_zv(zvol_state_t *);
 static int zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio);
 static int zvol_dumpify(zvol_state_t *zv);
@@ -386,6 +391,24 @@ zvol_create_cb(objset_t *os, void *arg, 
 }
 
 /*
+ * Replay a TX_TRUNCATE ZIL transaction if asked.  TX_TRUNCATE is how we
+ * implement DKIOCFREE/free-long-range.
+ */
+static int
+zvol_replay_truncate(zvol_state_t *zv, lr_truncate_t *lr, boolean_t byteswap)
+{
+       uint64_t offset, length;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       offset = lr->lr_offset;
+       length = lr->lr_length;
+
+       return (dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, offset, length));
+}
+
+/*
  * Replay a TX_WRITE ZIL transaction that didn't get committed
  * after a system failure
  */
@@ -435,7 +458,7 @@ zvol_replay_err(zvol_state_t *zv, lr_t *
 
 /*
  * Callback vectors for replaying records.
- * Only TX_WRITE is needed for zvol.
+ * Only TX_WRITE and TX_TRUNCATE are needed for zvol.
  */
 zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
        zvol_replay_err,        /* 0 no such transaction type */
@@ -448,7 +471,7 @@ zil_replay_func_t *zvol_replay_vector[TX
        zvol_replay_err,        /* TX_LINK */
        zvol_replay_err,        /* TX_RENAME */
        zvol_replay_write,      /* TX_WRITE */
-       zvol_replay_err,        /* TX_TRUNCATE */
+       zvol_replay_truncate,   /* TX_TRUNCATE */
        zvol_replay_err,        /* TX_SETATTR */
        zvol_replay_err,        /* TX_ACL */
        zvol_replay_err,        /* TX_CREATE_ACL */
@@ -1316,6 +1339,21 @@ zvol_strategy(struct bio *bp)
        rl = zfs_range_lock(&zv->zv_znode, off, resid,
            doread ? RL_READER : RL_WRITER);
 
+       if (bp->bio_cmd == BIO_DELETE) {
+               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, off, resid, B_TRUE);
+                       dmu_tx_commit(tx);
+                       error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ,
+                           off, resid);
+                       resid = 0;
+               }
+               goto unlock;
+       }
+
        while (resid != 0 && off < volsize) {
                size_t size = MIN(resid, zvol_maxphys);
 #ifdef illumos
@@ -1351,6 +1389,7 @@ zvol_strategy(struct bio *bp)
                addr += size;
                resid -= size;
        }
+unlock:
        zfs_range_unlock(rl);
 
        bp->bio_completed = bp->bio_length - resid;
@@ -1648,9 +1687,36 @@ zvol_log_write_minor(void *minor_hdl, dm
 /*
  * END entry points to allow external callers access to the volume.
  */
+#endif /* sun */
 
 /*
+ * Log a DKIOCFREE/free-long-range to the ZIL with TX_TRUNCATE.
+ */
+static void
+zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off, uint64_t len,
+    boolean_t sync)
+{
+       itx_t *itx;
+       lr_truncate_t *lr;
+       zilog_t *zilog = zv->zv_zilog;
+
+       if (zil_replaying(zilog, tx))
+               return;
+
+       itx = zil_itx_create(TX_TRUNCATE, sizeof (*lr));
+       lr = (lr_truncate_t *)&itx->itx_lr;
+       lr->lr_foid = ZVOL_OBJ;
+       lr->lr_offset = off;
+       lr->lr_length = len;
+
+       itx->itx_sync = sync;
+       zil_itx_assign(zilog, itx, tx);
+}
+
+#ifdef sun
+/*
  * Dirtbag ioctls to support mkfs(1M) for UFS filesystems.  See dkio(7I).
+ * Also a dirtbag dkio ioctl for unmap/free-block functionality.
  */
 /*ARGSUSED*/
 int
@@ -2271,12 +2337,12 @@ zvol_geom_start(struct bio *bp)
                break;
        case BIO_READ:
        case BIO_WRITE:
+       case BIO_DELETE:
                if (!THREAD_CAN_SLEEP())
                        goto enqueue;
                zvol_strategy(bp);
                break;
        case BIO_GETATTR:
-       case BIO_DELETE:
        default:
                g_io_deliver(bp, EOPNOTSUPP);
                break;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to