Add -p switch to "zpool get"
[zfs.git] / module / zfs / dsl_deleg.c
index 5d76ff5..294932c 100644 (file)
@@ -19,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 /*
@@ -75,8 +75,6 @@
 #include <sys/dsl_synctask.h>
 #include <sys/dsl_deleg.h>
 #include <sys/spa.h>
-#include <sys/spa_impl.h>
-#include <sys/zio_checksum.h> /* for the default checksum value */
 #include <sys/zap.h>
 #include <sys/fs/zfs.h>
 #include <sys/cred.h>
@@ -99,13 +97,13 @@ dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
        if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
                return (error);
 
-       while (whopair = nvlist_next_nvpair(nvp, whopair)) {
+       while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
                nvlist_t *perms;
                nvpair_t *permpair = NULL;
 
                VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
 
-               while (permpair = nvlist_next_nvpair(perms, permpair)) {
+               while ((permpair = nvlist_next_nvpair(perms, permpair))) {
                        const char *perm = nvpair_name(permpair);
 
                        if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
@@ -136,7 +134,7 @@ dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
        (void) snprintf(idstr, sizeof (idstr), "%lld",
            (longlong_t)crgetuid(cr));
 
-       while (whopair = nvlist_next_nvpair(nvp, whopair)) {
+       while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
                zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
 
                if (type != ZFS_DELEG_USER &&
@@ -150,7 +148,7 @@ dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
 }
 
 static void
-dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
+dsl_deleg_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 {
        dsl_dir_t *dd = arg1;
        nvlist_t *nvp = arg2;
@@ -164,7 +162,7 @@ dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
                    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
        }
 
-       while (whopair = nvlist_next_nvpair(nvp, whopair)) {
+       while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
                const char *whokey = nvpair_name(whopair);
                nvlist_t *perms;
                nvpair_t *permpair = NULL;
@@ -173,20 +171,18 @@ dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
                VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
 
                if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
-                       jumpobj = zap_create(mos, DMU_OT_DSL_PERMS,
-                           DMU_OT_NONE, 0, tx);
-                       VERIFY(zap_update(mos, zapobj,
-                           whokey, 8, 1, &jumpobj, tx) == 0);
+                       jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS,
+                           zapobj, whokey, tx);
                }
 
-               while (permpair = nvlist_next_nvpair(perms, permpair)) {
+               while ((permpair = nvlist_next_nvpair(perms, permpair))) {
                        const char *perm = nvpair_name(permpair);
                        uint64_t n = 0;
 
                        VERIFY(zap_update(mos, jumpobj,
                            perm, 8, 1, &n, tx) == 0);
-                       spa_history_internal_log(LOG_DS_PERM_UPDATE,
-                           dd->dd_pool->dp_spa, tx, cr,
+                       spa_history_log_internal(LOG_DS_PERM_UPDATE,
+                           dd->dd_pool->dp_spa, tx,
                            "%s %s dataset = %llu", whokey, perm,
                            dd->dd_phys->dd_head_dataset_obj);
                }
@@ -194,7 +190,7 @@ dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
 }
 
 static void
-dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
+dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 {
        dsl_dir_t *dd = arg1;
        nvlist_t *nvp = arg2;
@@ -205,7 +201,7 @@ dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
        if (zapobj == 0)
                return;
 
-       while (whopair = nvlist_next_nvpair(nvp, whopair)) {
+       while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
                const char *whokey = nvpair_name(whopair);
                nvlist_t *perms;
                nvpair_t *permpair = NULL;
@@ -217,8 +213,8 @@ dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
                                (void) zap_remove(mos, zapobj, whokey, tx);
                                VERIFY(0 == zap_destroy(mos, jumpobj, tx));
                        }
-                       spa_history_internal_log(LOG_DS_PERM_WHO_REMOVE,
-                           dd->dd_pool->dp_spa, tx, cr,
+                       spa_history_log_internal(LOG_DS_PERM_WHO_REMOVE,
+                           dd->dd_pool->dp_spa, tx,
                            "%s dataset = %llu", whokey,
                            dd->dd_phys->dd_head_dataset_obj);
                        continue;
@@ -227,7 +223,7 @@ dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
                if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
                        continue;
 
-               while (permpair = nvlist_next_nvpair(perms, permpair)) {
+               while ((permpair = nvlist_next_nvpair(perms, permpair))) {
                        const char *perm = nvpair_name(permpair);
                        uint64_t n = 0;
 
@@ -238,8 +234,8 @@ dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
                                VERIFY(0 == zap_destroy(mos,
                                    jumpobj, tx));
                        }
-                       spa_history_internal_log(LOG_DS_PERM_REMOVE,
-                           dd->dd_pool->dp_spa, tx, cr,
+                       spa_history_log_internal(LOG_DS_PERM_REMOVE,
+                           dd->dd_pool->dp_spa, tx,
                            "%s %s dataset = %llu", whokey, perm,
                            dd->dd_phys->dd_head_dataset_obj);
                }
@@ -264,7 +260,7 @@ dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
                return (ENOTSUP);
        }
 
-       while (whopair = nvlist_next_nvpair(nvp, whopair))
+       while ((whopair = nvlist_next_nvpair(nvp, whopair)))
                blocks_modified++;
 
        error = dsl_sync_task_do(dd->dd_pool, NULL,
@@ -299,6 +295,9 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
        dsl_pool_t *dp;
        int error;
        objset_t *mos;
+       zap_cursor_t *basezc, *zc;
+       zap_attribute_t *baseza, *za;
+       char *source;
 
        error = dsl_dir_open(ddname, FTAG, &startdd, NULL);
        if (error)
@@ -307,15 +306,17 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
        dp = startdd->dd_pool;
        mos = dp->dp_meta_objset;
 
+       zc = kmem_alloc(sizeof(zap_cursor_t), KM_SLEEP);
+       za = kmem_alloc(sizeof(zap_attribute_t), KM_SLEEP);
+       basezc = kmem_alloc(sizeof(zap_cursor_t), KM_SLEEP);
+       baseza = kmem_alloc(sizeof(zap_attribute_t), KM_SLEEP);
+       source = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, KM_SLEEP);
        VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 
        rw_enter(&dp->dp_config_rwlock, RW_READER);
        for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
-               zap_cursor_t basezc;
-               zap_attribute_t baseza;
                nvlist_t *sp_nvp;
                uint64_t n;
-               char source[MAXNAMELEN];
 
                if (dd->dd_phys->dd_deleg_zapobj &&
                    (zap_count(mos, dd->dd_phys->dd_deleg_zapobj,
@@ -326,32 +327,30 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
                        continue;
                }
 
-               for (zap_cursor_init(&basezc, mos,
+               for (zap_cursor_init(basezc, mos,
                    dd->dd_phys->dd_deleg_zapobj);
-                   zap_cursor_retrieve(&basezc, &baseza) == 0;
-                   zap_cursor_advance(&basezc)) {
-                       zap_cursor_t zc;
-                       zap_attribute_t za;
+                   zap_cursor_retrieve(basezc, baseza) == 0;
+                   zap_cursor_advance(basezc)) {
                        nvlist_t *perms_nvp;
 
-                       ASSERT(baseza.za_integer_length == 8);
-                       ASSERT(baseza.za_num_integers == 1);
+                       ASSERT(baseza->za_integer_length == 8);
+                       ASSERT(baseza->za_num_integers == 1);
 
                        VERIFY(nvlist_alloc(&perms_nvp,
                            NV_UNIQUE_NAME, KM_SLEEP) == 0);
-                       for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
-                           zap_cursor_retrieve(&zc, &za) == 0;
-                           zap_cursor_advance(&zc)) {
+                       for (zap_cursor_init(zc, mos, baseza->za_first_integer);
+                           zap_cursor_retrieve(zc, za) == 0;
+                           zap_cursor_advance(zc)) {
                                VERIFY(nvlist_add_boolean(perms_nvp,
-                                   za.za_name) == 0);
+                                   za->za_name) == 0);
                        }
-                       zap_cursor_fini(&zc);
-                       VERIFY(nvlist_add_nvlist(sp_nvp, baseza.za_name,
+                       zap_cursor_fini(zc);
+                       VERIFY(nvlist_add_nvlist(sp_nvp, baseza->za_name,
                            perms_nvp) == 0);
                        nvlist_free(perms_nvp);
                }
 
-               zap_cursor_fini(&basezc);
+               zap_cursor_fini(basezc);
 
                dsl_dir_name(dd, source);
                VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0);
@@ -359,6 +358,12 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
        }
        rw_exit(&dp->dp_config_rwlock);
 
+       kmem_free(source, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
+       kmem_free(baseza, sizeof(zap_attribute_t));
+       kmem_free(basezc, sizeof(zap_cursor_t));
+       kmem_free(za, sizeof(zap_attribute_t));
+       kmem_free(zc, sizeof(zap_cursor_t));
+
        dsl_dir_close(startdd, FTAG);
        return (0);
 }
@@ -528,12 +533,13 @@ dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
 }
 
 /*
- * Check if user has requested permission.
+ * Check if user has requested permission.  If descendent is set, must have
+ * descendent perms.
  */
 int
-dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
+dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm,
+    cred_t *cr)
 {
-       dsl_dataset_t *ds;
        dsl_dir_t *dd;
        dsl_pool_t *dp;
        void *cookie;
@@ -543,25 +549,17 @@ dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
        avl_tree_t permsets;
        perm_set_t *setnode;
 
-       error = dsl_dataset_hold(dsname, FTAG, &ds);
-       if (error)
-               return (error);
-
        dp = ds->ds_dir->dd_pool;
        mos = dp->dp_meta_objset;
 
-       if (dsl_delegation_on(mos) == B_FALSE) {
-               dsl_dataset_rele(ds, FTAG);
+       if (dsl_delegation_on(mos) == B_FALSE)
                return (ECANCELED);
-       }
 
        if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
-           SPA_VERSION_DELEGATED_PERMS) {
-               dsl_dataset_rele(ds, FTAG);
+           SPA_VERSION_DELEGATED_PERMS)
                return (EPERM);
-       }
 
-       if (dsl_dataset_is_snapshot(ds)) {
+       if (dsl_dataset_is_snapshot(ds) || descendent) {
                /*
                 * Snapshots are treated as descendents only,
                 * local permissions do not apply.
@@ -589,7 +587,7 @@ dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
 
                        if (dsl_prop_get_dd(dd,
                            zfs_prop_to_name(ZFS_PROP_ZONED),
-                           8, 1, &zoned, NULL) != 0)
+                           8, 1, &zoned, NULL, B_FALSE) != 0)
                                break;
                        if (!zoned)
                                break;
@@ -636,7 +634,6 @@ again:
        error = EPERM;
 success:
        rw_exit(&dp->dp_config_rwlock);
-       dsl_dataset_rele(ds, FTAG);
 
        cookie = NULL;
        while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
@@ -645,6 +642,22 @@ success:
        return (error);
 }
 
+int
+dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
+{
+       dsl_dataset_t *ds;
+       int error;
+
+       error = dsl_dataset_hold(dsname, FTAG, &ds);
+       if (error)
+               return (error);
+
+       error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr);
+       dsl_dataset_rele(ds, FTAG);
+
+       return (error);
+}
+
 /*
  * Other routines.
  */
@@ -739,5 +752,10 @@ dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
 boolean_t
 dsl_delegation_on(objset_t *os)
 {
-       return (os->os->os_spa->spa_delegation);
+       return (!!spa_delegation(os->os_spa));
 }
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dsl_deleg_get);
+EXPORT_SYMBOL(dsl_deleg_set);
+#endif