]> granicus.if.org Git - zfs/commitdiff
Fix small sysfs leak
authorBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 26 Sep 2018 16:50:58 +0000 (09:50 -0700)
committerGitHub <noreply@github.com>
Wed, 26 Sep 2018 16:50:58 +0000 (09:50 -0700)
When zfs_kobj_init() is called with an attr_cnt of 0 only the
kobj->zko_default_attrs is allocated.  It subsequently won't
get freed in zfs_kobj_release since the free is wrapped in
a kobj->zko_attr_count != 0 conditional.

Split the block in zfs_kobj_release() to make sure the
kobj->zko_default_attrs are freed in this case.

Additionally, fix a minor spelling mistake and typo in
zfs_kobj_init() which could also cause a leak but in practice
is almost certain not to fail.

Reviewed-by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed-by: Tim Chase <tim@chase2k.com>
Reviewed-by: John Gallagher <john.gallagher@delphix.com>
Reviewed-by: Don Brady <don.brady@delphix.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #7957

module/zfs/zfs_sysfs.c

index 42822b2f230f4009fc630eaae4f1350dbc69bce0..b17c91f6527c09a962940fcbf5bd3046fd047090 100644 (file)
@@ -102,7 +102,7 @@ typedef ssize_t     (*sysfs_show_func)(struct kobject *, struct attribute *,
 static void
 zfs_kobj_fini(zfs_mod_kobj_t *zkobj)
 {
-       /* finialize any child kobjects */
+       /* finalize any child kobjects */
        if (zkobj->zko_child_count != 0) {
                ASSERT(zkobj->zko_children);
                for (int i = 0; i < zkobj->zko_child_count; i++)
@@ -119,18 +119,19 @@ zfs_kobj_release(struct kobject *kobj)
 {
        zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj);
 
-       if (zkobj->zko_attr_count != 0) {
-               ASSERT(zkobj->zko_attr_list);
-               ASSERT(zkobj->zko_default_attrs);
-
+       if (zkobj->zko_attr_list != NULL) {
+               ASSERT3S(zkobj->zko_attr_count, !=, 0);
                kmem_free(zkobj->zko_attr_list,
                    ATTR_TABLE_SIZE(zkobj->zko_attr_count));
+               zkobj->zko_attr_list = NULL;
+       }
+
+       if (zkobj->zko_default_attrs != NULL) {
                kmem_free(zkobj->zko_default_attrs,
                    DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
-               zkobj->zko_attr_count = 0;
-               zkobj->zko_attr_list = NULL;
                zkobj->zko_default_attrs = NULL;
        }
+
        if (zkobj->zko_child_count != 0) {
                ASSERT(zkobj->zko_children);
 
@@ -139,6 +140,8 @@ zfs_kobj_release(struct kobject *kobj)
                zkobj->zko_child_count = 0;
                zkobj->zko_children = NULL;
        }
+
+       zkobj->zko_attr_count = 0;
 }
 
 static void
@@ -170,7 +173,7 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
        zkobj->zko_default_attrs = kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt),
            KM_SLEEP);
        if (zkobj->zko_default_attrs == NULL) {
-               if (zkobj->zko_attr_list) {
+               if (zkobj->zko_attr_list != NULL) {
                        kmem_free(zkobj->zko_attr_list,
                            ATTR_TABLE_SIZE(attr_cnt));
                }
@@ -183,9 +186,11 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
                zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
                    KM_SLEEP);
                if (zkobj->zko_children == NULL) {
-                       if (attr_cnt > 0) {
-                               kmem_free(zkobj->zko_attr_list,
+                       if (zkobj->zko_default_attrs != NULL) {
+                               kmem_free(zkobj->zko_default_attrs,
                                    DEFAULT_ATTR_SIZE(attr_cnt));
+                       }
+                       if (zkobj->zko_attr_list != NULL) {
                                kmem_free(zkobj->zko_attr_list,
                                    ATTR_TABLE_SIZE(attr_cnt));
                        }