Fix stack dsl_dataset_destroy()
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 26 Aug 2010 17:52:40 +0000 (10:52 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 31 Aug 2010 15:38:48 +0000 (08:38 -0700)
Move dsl_dataset_t local variable from the stack to the heap.
This reduces the stack usage of this function from 2048 bytes
to 176 bytes for x84_64 arches.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
module/zfs/dsl_dataset.c

index 4edf342..96a8b66 100644 (file)
@@ -1055,7 +1055,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
        dsl_dir_t *dd;
        uint64_t obj;
        struct dsl_ds_destroyarg dsda = { 0 };
-       dsl_dataset_t dummy_ds = { 0 };
+       dsl_dataset_t *dummy_ds;
 
        dsda.ds = ds;
 
@@ -1075,8 +1075,9 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
        }
 
        dd = ds->ds_dir;
-       dummy_ds.ds_dir = dd;
-       dummy_ds.ds_object = ds->ds_object;
+       dummy_ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
+       dummy_ds->ds_dir = dd;
+       dummy_ds->ds_object = ds->ds_object;
 
        /*
         * Check for errors and mark this ds as inconsistent, in
@@ -1085,11 +1086,11 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
        err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check,
            dsl_dataset_destroy_begin_sync, ds, NULL, 0);
        if (err)
-               goto out;
+               goto out_free;
 
        err = dmu_objset_from_ds(ds, &os);
        if (err)
-               goto out;
+               goto out_free;
 
        /*
         * remove the objects in open context, so that we won't
@@ -1104,7 +1105,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
                (void) dmu_free_object(os, obj);
        }
        if (err != ESRCH)
-               goto out;
+               goto out_free;
 
        /*
         * Only the ZIL knows how to free log blocks.
@@ -1134,7 +1135,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
        rw_exit(&dd->dd_pool->dp_config_rwlock);
 
        if (err)
-               goto out;
+               goto out_free;
 
        /*
         * Blow away the dsl_dir + head dataset.
@@ -1150,7 +1151,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
                        err = dsl_dataset_origin_rm_prep(&dsda, tag);
                        if (err) {
                                dsl_dir_close(dd, FTAG);
-                               goto out;
+                               goto out_free;
                        }
                }
 
@@ -1158,7 +1159,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
                dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
                    dsl_dataset_destroy_sync, &dsda, tag, 0);
                dsl_sync_task_create(dstg, dsl_dir_destroy_check,
-                   dsl_dir_destroy_sync, &dummy_ds, FTAG, 0);
+                   dsl_dir_destroy_sync, dummy_ds, FTAG, 0);
                err = dsl_sync_task_group_wait(dstg);
                dsl_sync_task_group_destroy(dstg);
 
@@ -1181,6 +1182,9 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
        /* if it is successful, dsl_dir_destroy_sync will close the dd */
        if (err)
                dsl_dir_close(dd, FTAG);
+
+out_free:
+       kmem_free(dummy_ds, sizeof (dsl_dataset_t));
 out:
        dsl_dataset_disown(ds, tag);
        return (err);