kmem_zalloc(..., KM_SLEEP) will never fail
[zfs.git] / module / zfs / zfs_ioctl.c
index a382de7..1226b2c 100644 (file)
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Portions Copyright 2011 Martin Matuska
  * Portions Copyright 2012 Pawel Jakub Dawidek <pawel@dawidek.net>
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -53,6 +56,7 @@
 #include <sys/dsl_prop.h>
 #include <sys/dsl_deleg.h>
 #include <sys/dmu_objset.h>
+#include <sys/dmu_impl.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/sunldi.h>
@@ -72,6 +76,8 @@
 #include <sys/dmu_objset.h>
 #include <sys/fm/util.h>
 
+#include <sys/zfeature.h>
+
 #include <linux/miscdevice.h>
 
 #include "zfs_namecheck.h"
@@ -125,6 +131,12 @@ static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *,
     boolean_t *);
 int zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t **);
 
+static int zfs_prop_activate_feature(dsl_pool_t *dp, zfeature_info_t *feature);
+static int zfs_prop_activate_feature_check(void *arg1, void *arg2,
+    dmu_tx_t *tx);
+static void zfs_prop_activate_feature_sync(void *arg1, void *arg2,
+    dmu_tx_t *tx);
+
 static void
 history_str_free(char *buf)
 {
@@ -1105,6 +1117,8 @@ get_zfs_sb(const char *dsname, zfs_sb_t **zsbp)
 /*
  * Find a zfs_sb_t for a mounted filesystem, or create our own, in which
  * case its z_sb will be NULL, and it will be opened as the owner.
+ * If 'writer' is set, the z_teardown_lock will be held for RW_WRITER,
+ * which prevents all inode ops from running.
  */
 static int
 zfs_sb_hold(const char *name, void *tag, zfs_sb_t **zsbp, boolean_t writer)
@@ -1168,7 +1182,7 @@ zfs_ioc_pool_create(zfs_cmd_t *zc)
 
                (void) nvlist_lookup_uint64(props,
                    zpool_prop_to_name(ZPOOL_PROP_VERSION), &version);
-               if (version < SPA_VERSION_INITIAL || version > SPA_VERSION) {
+               if (!SPA_VERSION_IS_SUPPORTED(version)) {
                        error = EINVAL;
                        goto pool_props_bad;
                }
@@ -1295,6 +1309,15 @@ zfs_ioc_pool_configs(zfs_cmd_t *zc)
        return (error);
 }
 
+/*
+ * inputs:
+ * zc_name             name of the pool
+ *
+ * outputs:
+ * zc_cookie           real errno
+ * zc_nvlist_dst       config nvlist
+ * zc_nvlist_dst_size  size of config nvlist
+ */
 static int
 zfs_ioc_pool_stats(zfs_cmd_t *zc)
 {
@@ -1396,7 +1419,8 @@ zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
        if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
                return (error);
 
-       if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) {
+       if (zc->zc_cookie < spa_version(spa) ||
+           !SPA_VERSION_IS_SUPPORTED(zc->zc_cookie)) {
                spa_close(spa, FTAG);
                return (EINVAL);
        }
@@ -1755,7 +1779,7 @@ zfs_ioc_objset_stats_impl(zfs_cmd_t *zc, objset_t *os)
                        error = zvol_get_stats(os, nv);
                        if (error == EIO)
                                return (error);
-                       VERIFY3S(error, ==, 0);
+                       VERIFY0(error);
                }
                if (error == 0)
                        error = put_nvlist(zc, nv);
@@ -2160,6 +2184,9 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
        case ZFS_PROP_VOLSIZE:
                err = zvol_set_volsize(dsname, intval);
                break;
+       case ZFS_PROP_SNAPDEV:
+               err = zvol_set_snapdev(dsname, intval);
+               break;
        case ZFS_PROP_VERSION:
        {
                zfs_sb_t *zsb;
@@ -2181,6 +2208,40 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
                }
                break;
        }
+       case ZFS_PROP_COMPRESSION:
+       {
+               if (intval == ZIO_COMPRESS_LZ4) {
+                       zfeature_info_t *feature =
+                           &spa_feature_table[SPA_FEATURE_LZ4_COMPRESS];
+                       spa_t *spa;
+                       dsl_pool_t *dp;
+
+                       if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                               return (err);
+
+                       dp = spa->spa_dsl_pool;
+
+                       /*
+                        * Setting the LZ4 compression algorithm activates
+                        * the feature.
+                        */
+                       if (!spa_feature_is_active(spa, feature)) {
+                               if ((err = zfs_prop_activate_feature(dp,
+                                   feature)) != 0) {
+                                       spa_close(spa, FTAG);
+                                       return (err);
+                               }
+                       }
+
+                       spa_close(spa, FTAG);
+               }
+               /*
+                * We still want the default set action to be performed in the
+                * caller, we only performed zfeature settings here.
+                */
+               err = -1;
+               break;
+       }
 
        default:
                err = -1;
@@ -3401,6 +3462,22 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
                            SPA_VERSION_ZLE_COMPRESSION))
                                return (ENOTSUP);
 
+                       if (intval == ZIO_COMPRESS_LZ4) {
+                               zfeature_info_t *feature =
+                                   &spa_feature_table[
+                                   SPA_FEATURE_LZ4_COMPRESS];
+                               spa_t *spa;
+
+                               if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                                       return (err);
+
+                               if (!spa_feature_is_enabled(spa, feature)) {
+                                       spa_close(spa, FTAG);
+                                       return (ENOTSUP);
+                               }
+                               spa_close(spa, FTAG);
+                       }
+
                        /*
                         * If this is a bootable dataset then
                         * verify that the compression algorithm
@@ -3447,6 +3524,56 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
 }
 
 /*
+ * Activates a feature on a pool in response to a property setting. This
+ * creates a new sync task which modifies the pool to reflect the feature
+ * as being active.
+ */
+static int
+zfs_prop_activate_feature(dsl_pool_t *dp, zfeature_info_t *feature)
+{
+       int err;
+
+       /* EBUSY here indicates that the feature is already active */
+       err = dsl_sync_task_do(dp, zfs_prop_activate_feature_check,
+           zfs_prop_activate_feature_sync, dp->dp_spa, feature, 2);
+
+       if (err != 0 && err != EBUSY)
+               return (err);
+       else
+               return (0);
+}
+
+/*
+ * Checks for a race condition to make sure we don't increment a feature flag
+ * multiple times.
+ */
+/*ARGSUSED*/
+static int
+zfs_prop_activate_feature_check(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+       spa_t *spa = arg1;
+       zfeature_info_t *feature = arg2;
+
+       if (!spa_feature_is_active(spa, feature))
+               return (0);
+       else
+               return (EBUSY);
+}
+
+/*
+ * The callback invoked on feature activation in the sync task caused by
+ * zfs_prop_activate_feature.
+ */
+static void
+zfs_prop_activate_feature_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+       spa_t *spa = arg1;
+       zfeature_info_t *feature = arg2;
+
+       spa_feature_incr(spa, feature, tx);
+}
+
+/*
  * Removes properties from the given props list that fail permission checks
  * needed to clear them and to restore them in case of a receive error. For each
  * property, make sure we have both set and inherit permissions.
@@ -3890,8 +4017,8 @@ zfs_ioc_send(zfs_cmd_t *zc)
                }
 
                off = fp->f_offset;
-               error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj,
-                   fp->f_vnode, &off);
+               error = dmu_send(tosnap, fromsnap, zc->zc_obj,
+                   zc->zc_cookie, fp->f_vnode, &off);
 
                if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
                        fp->f_offset = off;
@@ -3903,6 +4030,50 @@ zfs_ioc_send(zfs_cmd_t *zc)
        return (error);
 }
 
+/*
+ * inputs:
+ * zc_name     name of snapshot on which to report progress
+ * zc_cookie   file descriptor of send stream
+ *
+ * outputs:
+ * zc_cookie   number of bytes written in send stream thus far
+ */
+static int
+zfs_ioc_send_progress(zfs_cmd_t *zc)
+{
+       dsl_dataset_t *ds;
+       dmu_sendarg_t *dsp = NULL;
+       int error;
+
+       if ((error = dsl_dataset_hold(zc->zc_name, FTAG, &ds)) != 0)
+               return (error);
+
+       mutex_enter(&ds->ds_sendstream_lock);
+
+       /*
+        * Iterate over all the send streams currently active on this dataset.
+        * If there's one which matches the specified file descriptor _and_ the
+        * stream was started by the current process, return the progress of
+        * that stream.
+        */
+
+       for (dsp = list_head(&ds->ds_sendstreams); dsp != NULL;
+           dsp = list_next(&ds->ds_sendstreams, dsp)) {
+               if (dsp->dsa_outfd == zc->zc_cookie &&
+                   dsp->dsa_proc->group_leader == curproc->group_leader)
+                       break;
+       }
+
+       if (dsp != NULL)
+               zc->zc_cookie = *(dsp->dsa_off);
+       else
+               error = ENOENT;
+
+       mutex_exit(&ds->ds_sendstream_lock);
+       dsl_dataset_rele(ds, FTAG);
+       return (error);
+}
+
 static int
 zfs_ioc_inject_fault(zfs_cmd_t *zc)
 {
@@ -4037,6 +4208,32 @@ zfs_ioc_clear(zfs_cmd_t *zc)
        return (error);
 }
 
+static int
+zfs_ioc_pool_reopen(zfs_cmd_t *zc)
+{
+       spa_t *spa;
+       int error;
+
+       error = spa_open(zc->zc_name, &spa, FTAG);
+       if (error)
+               return (error);
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+
+       /*
+        * If a resilver is already in progress then set the
+        * spa_scrub_reopen flag to B_TRUE so that we don't restart
+        * the scan as a side effect of the reopen. Otherwise, let
+        * vdev_open() decided if a resilver is required.
+        */
+       spa->spa_scrub_reopen = dsl_scan_resilvering(spa->spa_dsl_pool);
+       vdev_reopen(spa->spa_root_vdev);
+       spa->spa_scrub_reopen = B_FALSE;
+
+       (void) spa_vdev_state_exit(spa, NULL, 0);
+       spa_close(spa, FTAG);
+       return (0);
+}
 /*
  * inputs:
  * zc_name     name of filesystem
@@ -4831,6 +5028,10 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
            POOL_CHECK_SUSPENDED },
        { zfs_ioc_space_snaps, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
            POOL_CHECK_SUSPENDED },
+       { zfs_ioc_pool_reopen, zfs_secpolicy_config, POOL_NAME, B_TRUE,
+           POOL_CHECK_SUSPENDED },
+       { zfs_ioc_send_progress, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
+           POOL_CHECK_NONE }
 };
 
 int
@@ -4935,8 +5136,6 @@ zfsdev_state_init(struct file *filp)
                 return (ENXIO);
 
        zs = kmem_zalloc( sizeof(zfsdev_state_t), KM_SLEEP);
-       if (zs == NULL)
-               return (ENOMEM);
 
        zs->zs_file = filp;
        zs->zs_minor = minor;