]> granicus.if.org Git - zfs/commitdiff
Fix the creation of ZPOOL_HIST_CMD pool history entries.
authorTim Chase <tim@chase2k.com>
Mon, 23 Dec 2013 20:06:34 +0000 (14:06 -0600)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 7 Jan 2014 17:00:26 +0000 (09:00 -0800)
Move the libzfs_fini() after the zpool_log_history() call so the
ZPOOL_HIST_CMD entry can get written.

Fix the handling of saved_poolname in zfsdev_ioctl()
which was broken as part of the stack-reduction work in
a16878805388c4d96cb8a294de965071d138a47b.

Since ZoL destroys the TSD data in which the previously successful
ioctl()'s pool name is stored following every vop, the ZFS_IOC_LOG_HISTORY
ioctl has a very important restriction: it can only successfully write
a long entry following a successful ioctl() if no intervening vops have
been performed.  Some of zfs subcommands do perform intervening vops and
to do the logging themselves. At the moment, the "create" and "clone"
subcommands have been modified appropriately.

Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1998

cmd/zfs/zfs_main.c
module/zfs/zfs_ioctl.c

index 3f54985b9323571e17bc8d5763e920a9d49eddd4..cea42123812e10f2b861c0074adbe2142950a55a 100644 (file)
@@ -649,6 +649,11 @@ zfs_do_clone(int argc, char **argv)
        if (ret == 0) {
                zfs_handle_t *clone;
 
+               if (log_history) {
+                       (void) zpool_log_history(g_zfs, history_str);
+                       log_history = B_FALSE;
+               }
+
                clone = zfs_open(g_zfs, argv[1], ZFS_TYPE_DATASET);
                if (clone != NULL) {
                        if (zfs_get_type(clone) != ZFS_TYPE_VOLUME)
@@ -828,6 +833,11 @@ zfs_do_create(int argc, char **argv)
        if (zfs_create(g_zfs, argv[0], type, props) != 0)
                goto error;
 
+       if (log_history) {
+               (void) zpool_log_history(g_zfs, history_str);
+               log_history = B_FALSE;
+       }
+
        if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
                goto error;
 
@@ -6481,11 +6491,12 @@ main(int argc, char **argv)
                usage(B_FALSE);
                ret = 1;
        }
-       libzfs_fini(g_zfs);
 
        if (ret == 0 && log_history)
                (void) zpool_log_history(g_zfs, history_str);
 
+       libzfs_fini(g_zfs);
+
        /*
         * The 'ZFS_ABORT' environment variable causes us to dump core on exit
         * for the purposes of running ::findleaks.
index bf212dee82eb94ddc5f9516f704b57bace63e533..a061978dcee8907cf8b11b2a60db9c5187f07df4 100644 (file)
@@ -5558,9 +5558,9 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
 {
        zfs_cmd_t *zc;
        uint_t vecnum;
-       int error, rc, len, flag = 0;
+       int error, rc, len = 0, flag = 0;
        const zfs_ioc_vec_t *vec;
-       char *saved_poolname;
+       char *saved_poolname = NULL;
        nvlist_t *innvl = NULL;
 
        vecnum = cmd - ZFS_IOC_FIRST;
@@ -5576,7 +5576,6 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
                return (-SET_ERROR(EINVAL));
 
        zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP | KM_NODEBUG);
-       saved_poolname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 
        error = ddi_copyin((void *)arg, zc, sizeof (zfs_cmd_t), flag);
        if (error != 0) {
@@ -5626,9 +5625,9 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
                goto out;
 
        /* legacy ioctls can modify zc_name */
-       (void) strlcpy(saved_poolname, zc->zc_name, sizeof (saved_poolname));
-       len = strcspn(saved_poolname, "/@") + 1;
-       saved_poolname[len] = '\0';
+       len = strcspn(zc->zc_name, "/@#") + 1;
+       saved_poolname = kmem_alloc(len, KM_SLEEP);
+       (void) strlcpy(saved_poolname, zc->zc_name, len);
 
        if (vec->zvec_func != NULL) {
                nvlist_t *outnvl;
@@ -5693,10 +5692,12 @@ out:
                char *s = tsd_get(zfs_allow_log_key);
                if (s != NULL)
                        strfree(s);
-               (void) tsd_set(zfs_allow_log_key, strdup(saved_poolname));
+               (void) tsd_set(zfs_allow_log_key, saved_poolname);
+       } else {
+               if (saved_poolname != NULL)
+                       kmem_free(saved_poolname, len);
        }
 
-       kmem_free(saved_poolname, MAXNAMELEN);
        kmem_free(zc, sizeof (zfs_cmd_t));
        return (-error);
 }